Documentation ¶
Overview ¶
See the README on https://github.com/Cyphrme/Coze
This library exports some functions that may be helpful for other applications, but should not be considered apart of the Coze specification API.
- ECDSAToLowSSig
- IsLowS
- ToLowS
- Marshal
- MarshalPretty
Other auxiliary types and functions, like B64, are reasonable exports for package Coze, especially since compatible implementations are absent from the Go standard library.
Example (Iat_rvk_too_big) ¶
Demonstrates expectations for values that are non-integer, negative, or too large for rvk.
p := &Pay{} // 2^53 - 1 as a string which must error. err := json.Unmarshal([]byte(`{"rvk":"9007199254740991"}`), p) if err != nil { fmt.Println(err) } // 2^53 err = json.Unmarshal([]byte(`{"rvk":9007199254740992}`), p) if err != nil { fmt.Println(err) } // Negative 2^53 + 1 must error as rvk must be positive. err = json.Unmarshal([]byte(`{"rvk":-9007199254740991}`), p) if err != nil { fmt.Println(err) } // Finally, 2^53 - 1 as an integer which is okay. err = json.Unmarshal([]byte(`{"rvk":9007199254740991}`), p) if err != nil { fmt.Println(err) } fmt.Println(p)
Output: json: cannot unmarshal string into Go struct field pay2.rvk of type int64 Pay.UnmarshalJSON: values for iat and rvk must be between 0 and 2^53 - 1 Pay.UnmarshalJSON: values for iat and rvk must be between 0 and 2^53 - 1 {"rvk":9007199254740991}
Index ¶
- Constants
- Variables
- func Canon(raw json.RawMessage) (can []string, err error)
- func Canonical(input []byte, canon any) (b []byte, err error)
- func ECDSAToLowSSig(c *Key, coze *Coze) (err error)
- func IsLowS(c *Key, s *big.Int) (bool, error)
- func Marshal(i any) ([]byte, error)
- func MarshalPretty(i any) ([]byte, error)
- func ToLowS(c *Key, s *big.Int) error
- type Alg
- type B64
- func CanonicalHash(input []byte, canon any, hash HshAlg) (digest B64, err error)
- func Decode(b64 string) (B64, error)
- func GenCzd(hash HshAlg, cad B64, sig B64) (czd B64, err error)
- func Hash(h HshAlg, msg []byte) (digest B64, err error)
- func MustDecode(b64 string) B64
- func PadInts(r, s *big.Int, size int) (out B64)
- func Thumbprint(c *Key) (tmb B64, err error)
- type Coze
- type Crv
- type EncAlg
- type ErrJSONDuplicate
- type FamAlg
- type GenAlg
- type HshAlg
- type Key
- func (c *Key) Correct() (err error)
- func (c Key) IsRevoked() bool
- func (c *Key) Revoke() (coze *Coze, err error)
- func (c *Key) Sign(digest B64) (sig B64, err error)
- func (c *Key) SignCoze(cz *Coze) (err error)
- func (c *Key) SignPay(p *Pay) (coze *Coze, err error)
- func (c *Key) SignPayJSON(pay json.RawMessage) (coze *Coze, err error)
- func (c Key) String() string
- func (c *Key) Thumbprint() (err error)
- func (c *Key) ToPubEcdsa() (key *ecdsa.PublicKey)
- func (c *Key) UnmarshalJSON(b []byte) error
- func (c *Key) Valid() (valid bool)
- func (c *Key) Verify(digest, sig B64) (valid bool)
- func (c *Key) VerifyCoze(cz *Coze) (bool, error)
- type Marshaler
- type Params
- type Pay
- type SB64
- type SEAlg
- type SigAlg
- type Use
Examples ¶
- Package (Iat_rvk_too_big)
- Alg (JsonMarshal)
- Alg.Params
- Alg.Parse
- B64 (MarshalJSON)
- B64 (Non_strict_decode)
- B64 (UnmarshalJSON)
- B64 (Zero_nil)
- Canon
- Canonical
- Canonical (Slice)
- Canonical (Struct)
- CanonicalHash
- CanonicalHash (GenCad)
- CanonicalHash (InvalidAlg)
- CanonicalHash (Permutations)
- Coze (Embed)
- Coze (JsonMarshal)
- Coze (JsonMarshalPretty)
- Coze (JsonUnmarshal)
- Coze.Meta
- Coze.MetaWithAlg
- Coze.MetaWithAlg (Contextual)
- Coze.String
- Coze.UnmarshalJSON (Duplicate)
- Crv.Parse
- Decode
- ECDSAToLowSSig
- HshAlg (JsonMarshal)
- HshAlg (Print)
- Key (JsonMarshal)
- Key (JsonUnmarshal)
- Key (Unmarshal)
- Key.Correct
- Key.IsRevoked
- Key.Sign
- Key.SignCoze
- Key.SignPay
- Key.SignPayJSON
- Key.SignPayJSON (Empty)
- Key.String
- Key.Thumbprint
- Key.UnmarshalJSON (Duplicate)
- Key.Valid
- Key.Verify
- Key.Verify (Empty)
- Key.VerifyCoze
- Marshal (JsonRawMessage)
- MustDecode
- NewKey
- NewKey (Bad)
- NewKey (Valid)
- Pay (Embedded)
- Pay (JsonMarshalCustom)
- Pay (JsonUnmarshal)
- Pay (JsonUnmarshalCustom)
- Pay (JsonUnmarshalCustomManual)
- Pay.String (Custom)
- Pay.UnmarshalJSON (Duplicate)
- SB64
- Thumbprint
- Use.Parse
Constants ¶
const ( UnknownAlg Alg = "UnknownAlg" UnknownSigAlg SigAlg = "UnknownSigAlg" ES224 SigAlg = "ES224" ES256 SigAlg = "ES256" ES384 SigAlg = "ES384" ES512 SigAlg = "ES512" Ed25519 SigAlg = "Ed25519" Ed25519ph SigAlg = "Ed25519ph" Ed448 SigAlg = "Ed448" UnknownEncAlg EncAlg = "UnknownEncAlg" UnknownHshAlg HshAlg = "UnknownHshAlg" SHA224 HshAlg = "SHA-224" SHA256 HshAlg = "SHA-256" SHA384 HshAlg = "SHA-384" SHA512 HshAlg = "SHA-512" SHA3224 HshAlg = "SHA3-224" SHA3256 HshAlg = "SHA3-256" SHA3384 HshAlg = "SHA3-384" SHA3512 HshAlg = "SHA3-512" SHAKE128 HshAlg = "SHAKE128" SHAKE256 HshAlg = "SHAKE256" )
Variables ¶
var Algs = map[string]Alg{ string(UnknownAlg): Alg(UnknownAlg), string(UnknownSigAlg): Alg(UnknownSigAlg), string(ES224): Alg(ES224), string(ES256): Alg(ES256), string(ES384): Alg(ES384), string(ES512): Alg(ES512), string(Ed25519): Alg(Ed25519), string(Ed25519ph): Alg(Ed25519ph), string(Ed448): Alg(Ed448), string(UnknownEncAlg): Alg(UnknownEncAlg), string(UnknownHshAlg): Alg(UnknownHshAlg), string(SHA224): Alg(SHA224), string(SHA256): Alg(SHA256), string(SHA384): Alg(SHA384), string(SHA512): Alg(SHA512), string(SHA3224): Alg(SHA3224), string(SHA3256): Alg(SHA3256), string(SHA3384): Alg(SHA3384), string(SHA3512): Alg(SHA3512), string(SHAKE128): Alg(SHAKE128), string(SHAKE256): Alg(SHAKE256), }
Algs includes all algs, including unknown algs, SigAlg, EncAlg, and HshAlg.
var CzdCanon = []string{"cad", "sig"}
CzdCanon is the canon for a `czd`.
var EncAlgs = []EncAlg{ UnknownEncAlg, }
Encryption algs.
var HshAlgs = []HshAlg{ UnknownHshAlg, SHA224, SHA256, SHA384, SHA512, SHA3224, SHA3256, SHA3384, SHA3512, SHAKE128, SHAKE256, }
Hash algs.
var KeyCanon = []string{"alg", "x"}
KeyCanonSlice is the canonical form of a Coze key in slice form.
var SigAlgs = []SigAlg{ UnknownSigAlg, ES224, ES256, ES384, ES512, Ed25519, Ed25519ph, Ed448, }
Functions ¶
func Canon ¶
func Canon(raw json.RawMessage) (can []string, err error)
Canon returns the current canon from raw JSON.
It returns only top level fields with no recursion or promotion of embedded fields.
Example ¶
b := []byte(`{"z":"z", "a":"a"}`) can, err := Canon(b) if err != nil { panic(err) } fmt.Println(can)
Output: [z a]
func Canonical ¶
Canonical returns the canonical form. Input canon is optional and may be nil. If canon is nil, input JSON is only compactified.
Interface "canon" may be `[]string`, `struct“, or `nil`. If "canon" is a struct or slice it must be properly ordered. If canon is nil, json.Unmarshal will place the input into a UTF-8 ordered map.
In the Go version of Coze, the canonical form of a struct is (currently) achieved by unmarshalling and remarshalling.
Example ¶
ExampleCanonical.
var b []byte var err error type ABC struct { A string `json:"a"` B string `json:"b,omitempty"` C string `json:"c"` } // []byte (out of order) with nil canon. Missing field "b" should be omitted // from output. ca, err := Marshal(map[string]string{"c": "c", "a": "a"}) if err != nil { panic(err) } b, err = Canonical(ca, nil) if err != nil { panic(err) } fmt.Printf("Input: []byte; Canon: nil => %s\n", b) // []byte (out of order) with struct (in order) canon. Missing field "b" // should be omitted from output. ca, err = Marshal(map[string]string{"c": "c", "a": "a"}) if err != nil { panic(err) } b, err = Canonical(ca, new(ABC)) if err != nil { panic(err) } fmt.Printf("Input: []byte; Canon: struct => %s\n", b) // []byte (out of order) with struct (in order) canon. byteJSON := []byte(`{"c":"c", "a": "a"}`) b, err = Canonical(byteJSON, nil) if err != nil { panic(err) } fmt.Printf("Input: []byte; Canon: nil => %s\n", b)
Output: Input: []byte; Canon: nil => {"a":"a","c":"c"} Input: []byte; Canon: struct => {"a":"a","c":"c"} Input: []byte; Canon: nil => {"c":"c","a":"a"}
Example (Slice) ¶
dig, err := CanonicalHash([]byte(GoldenKeyString), KeyCanon, GoldenKey.Alg.Hash()) if err != nil { panic(err) } fmt.Println(dig)
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk
Example (Struct) ¶
ExampleCanonical_struct demonstrates using a given struct as a canon.
// KeyCanon is the canonical form of a Coze key in struct form. type KeyCanonStruct struct { Alg string `json:"alg"` X B64 `json:"x"` } kcs := new(KeyCanonStruct) dig, err := CanonicalHash([]byte(GoldenKeyString), kcs, GoldenKey.Alg.Hash()) if err != nil { panic(err) } fmt.Println(dig)
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk
func ECDSAToLowSSig ¶ added in v0.0.4
ECDSAToLowSSig generates low-S signature from existing ecdsa signatures (high or low-S). This is useful for migrating signatures from non-Coze systems that may have high S signatures. See Coze docs on low-S.
Example ¶
Example_ECDSAToLowSSig demonstrates converting non-coze compliant high S signatures to the canonicalized, coze compliant low-S form.
highSCozies := []string{ `{"pay":{},"sig":"9iesKUSV7L1-xz5yd3A94vCkKLmdOAnrcPXTU3_qeKSuk4RMG7Qz0KyubpATy0XA_fXrcdaxJTvXg6saaQQcVQ"}`, `{"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"mVw8N6ZncWcObVGvnwUMRIC6m2fbX3Sr1LlHMbj_tZ3ji1rNL-00pVaB12_fmlK3d_BVDipNQUsaRyIlGJudtg"}`, `{"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"cn6KNl4VQlk5MzmhYFVyyJoTOU57O5Bq-8r-yXXR6Ojfs0-6LFGd8j1Y6wiJAQrGpWj_RptsiEg49v95FsVWMQ"}`, `{"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"9KvWfOSIZUjW8Ie0jbdVdu9UlIP4TT4MXz3YyNW3fCTWXHnO1MPROwcXvfNZN_icOvMAK3vfsr2w-CeBozS81w"}`, } for _, s := range highSCozies { cz := new(Coze) err := json.Unmarshal([]byte(s), cz) if err != nil { panic(err) } v, _ := GoldenKey.VerifyCoze(cz) if v { panic("High S coze should not validate.") } err = ECDSAToLowSSig(&GoldenKey, cz) if err != nil { panic(err) } v, _ = GoldenKey.VerifyCoze(cz) if !v { panic("low-S coze should validate.") } fmt.Printf("%s\n", cz) }
Output: {"pay":{},"sig":"9iesKUSV7L1-xz5yd3A94vCkKLmdOAnrcPXTU3_qeKRRbHuy5EvMMFNRkW_sNLo-vvEPO9BmeUkcNh-ok18I_A"} {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"mVw8N6ZncWcObVGvnwUMRIC6m2fbX3Sr1LlHMbj_tZ0cdKUx0BLLW6l-KJAgZa1IRPaln3zKXTnZcqid48eHmw"} {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"cn6KNl4VQlk5MzmhYFVyyJoTOU57O5Bq-8r-yXXR6OggTLBE065iDsKnFPd2_vU5F337ZwurFjy6wstJ5Z3PIA"} {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"9KvWfOSIZUjW8Ie0jbdVdu9UlIP4TT4MXz3YyNW3fCQpo4YwKzwuxfjoQgymyAdjgfP6gis368dCwaNBWS5oeg"}
func Marshal ¶
Marshal is a JSON friendly marshaller. json.Marshal preemptively replaces the valid JSON and UTF-8 characters "&". "<", ">" with the "slash u" unicode escapes (e.g. \u0026) in the name of HTML friendliness, for example: https://play.golang.org/p/o2hiX0c62oN. As JSON is not HTML, preemptive HTML escaping is incorrect. (The JSON spec calls for no such measures and other industry encoders do no such preemptive escaping.) Where JSON may include these legitimate characters, like sanitized arbitrary user data, json.Marshal should not be used. The Go team is aware that the existing implementation has this and other concerns but has not yet released a new version. Joe Tsai is working on fixes in a yet-to-be-released Tailscale's "JSONv2" package, which we hope to use upon release. https://pkg.go.dev/github.com/go-json-experiment/json. The package also enumerates other JSON best practices that may be of concern for anyone concerned with the aforementioned issue. https://github.com/go-json-experiment/json#behavior-changes. See https://github.com/Cyphrme/Coze/issues/15 for other JSON encoding concerns.
Go structs already require unique fields, so unlike coze.UnmarshalJSON or pay.UnmarshalJSON, marshaling will not sanitize for duplicates.
Example (JsonRawMessage) ¶
ExampleMarshal_jsonRawMessage demonstrates using empty string, two quote characters, and nil for json.RawMessage. When using json.RawMessage, it should always be valid JSON or nil or otherwise it will result in an error.
o := json.RawMessage([]byte("")) // empty string anon := struct { Obj *json.RawMessage `json:"obj,omitempty"` }{ Obj: &o, } // Incorrect usage with pointer to a zero value string. // Pointer to empty string will fail Marshal since an empty string is not // valid JSON., while the value `""` will pass. b, err := Marshal(anon) // fails fmt.Printf("%s\n%+v\n", err, b) // Error is populated and b is empty because of error. // Correct usage with quotes characters. quotes := []byte("\"\"") // string with two quote characters anon.Obj = (*json.RawMessage)("es) b, err = Marshal(anon) if err != nil { panic(err) } fmt.Printf("%s\n", b) // Correct usage with with `nil`, which prints as the JSON "null". o = nil anon.Obj = &o b, err = Marshal(anon) if err != nil { panic(err) } fmt.Printf("%s\n", b)
Output: json: error calling MarshalJSON for type *json.RawMessage: unexpected end of JSON input [] {"obj":""} {"obj":null}
func MarshalPretty ¶
MarshalPretty uses 4 spaces for each level. Spaces are used instead of tabs because some applications display tabs as 8 spaces, which is excessive.
Types ¶
type Alg ¶ added in v0.0.1
type Alg string // Alg is for all "SpcAlg" cryptographic algorithms.
Alg is a declarative abstraction for cryptographic functions for Coze. For more on Alg, see the main Coze README.
Hierarchy for signing and hashing cryptographic functions. Naming is inspired by taxonomic rank.
- Level 0 species - "SpcAlg" (e.g.: ES256) (species)
- Level 1 genus - "GenAlg" (e.g.: ECDSA) (genus)
- Level 2 family - "FamAlg" (e.g.: EC) (family)
The value for a Coze `alg` is always a specific (species) algorithm, e.g. "ES256", and never any other rank, e.g. "ECDSA". The type `Alg` in this package may be any algorithm of any rank.
Cryptographic Signature/Encryption/Hashing hierarchy
- EC
- ECDSA
- ES224
- ES256
- ES384
- ES512
- EdDSA
- Ed25519
- Ed25519ph
- Ed448
- SHA
- SHA-2
- SHA-224
- SHA-256
- SHA-384
- SHA-512
- SHA-3
- SHA3-224
- SHA3-256
- SHA3-384
- SHA3-512
- SHAKE128
- SHAKE256
"SE" (singing, encryption) is the super type of signing and encryption and excludes hashing.
See the main Coze README for Coze supported and unsupported things.
Example (JsonMarshal) ¶
type algStruct struct { A Alg `json:"alg"` } b, err := Marshal(algStruct{A: Alg(ES256)}) if err != nil { panic(err) } fmt.Printf("%s\n", b) type seAlgStruct struct { A SEAlg `json:"alg"` } b, err = Marshal(seAlgStruct{A: SEAlg(ES256)}) if err != nil { panic(err) } fmt.Printf("%s\n", b)
Output: {"alg":"ES256"} {"alg":"ES256"}
func (Alg) Curve ¶ added in v0.0.1
Curve returns the curve for the given alg. Returns empty if alg does not have a curve.
func (Alg) Hash ¶ added in v0.0.1
Hash returns respective hashing algorithm if specified. If alg is a hashing algorithm, it returns itself.
func (Alg) Params ¶ added in v0.0.1
Params sets and returns a Params struct. See struct definition.
Example ¶
algs := []Alg{ Alg(ES224), Alg(ES256), Alg(ES384), Alg(ES512), Alg(Ed25519), Alg(Ed25519ph), Alg(Ed448), Alg(SHA224), Alg(SHA256), Alg(SHA384), Alg(SHA512), Alg(SHA3224), Alg(SHA3256), Alg(SHA3384), Alg(SHA3512), Alg(SHAKE128), Alg(SHAKE256), } fmt.Println(algs) for _, a := range algs { params := a.Params() b, _ := Marshal(params) fmt.Printf("%s\n", b) }
Output: [ES224 ES256 ES384 ES512 Ed25519 Ed25519ph Ed448 SHA-224 SHA-256 SHA-384 SHA-512 SHA3-224 SHA3-256 SHA3-384 SHA3-512 SHAKE128 SHAKE256] {"Name":"ES224","Genus":"ECDSA","Family":"EC","Use":"sig","Hash":"SHA-224","HashSize":28,"HashSizeB64":38,"XSize":56,"XSizeB64":75,"DSize":28,"DSizeB64":38,"Curve":"P-224","SigSize":56,"SigSizeB64":75} {"Name":"ES256","Genus":"ECDSA","Family":"EC","Use":"sig","Hash":"SHA-256","HashSize":32,"HashSizeB64":43,"XSize":64,"XSizeB64":86,"DSize":32,"DSizeB64":43,"Curve":"P-256","SigSize":64,"SigSizeB64":86} {"Name":"ES384","Genus":"ECDSA","Family":"EC","Use":"sig","Hash":"SHA-384","HashSize":48,"HashSizeB64":64,"XSize":96,"XSizeB64":128,"DSize":48,"DSizeB64":64,"Curve":"P-384","SigSize":96,"SigSizeB64":128} {"Name":"ES512","Genus":"ECDSA","Family":"EC","Use":"sig","Hash":"SHA-512","HashSize":64,"HashSizeB64":86,"XSize":132,"XSizeB64":176,"DSize":66,"DSizeB64":88,"Curve":"P-521","SigSize":132,"SigSizeB64":176} {"Name":"Ed25519","Genus":"EdDSA","Family":"EC","Use":"sig","Hash":"SHA-512","HashSize":64,"HashSizeB64":86,"XSize":32,"XSizeB64":43,"DSize":32,"DSizeB64":43,"Curve":"Curve25519","SigSize":64,"SigSizeB64":86} {"Name":"Ed25519ph","Genus":"EdDSA","Family":"EC","Use":"sig","Hash":"SHA-512","HashSize":64,"HashSizeB64":86,"XSize":32,"XSizeB64":43,"DSize":32,"DSizeB64":43,"Curve":"Curve25519","SigSize":64,"SigSizeB64":86} {"Name":"Ed448","Genus":"EdDSA","Family":"EC","Use":"sig","Hash":"SHAKE256","HashSize":64,"HashSizeB64":86,"XSize":57,"XSizeB64":76,"DSize":57,"DSizeB64":76,"Curve":"Curve448","SigSize":114,"SigSizeB64":152} {"Name":"SHA-224","Genus":"SHA2","Family":"SHA","Use":"hsh","Hash":"SHA-224","HashSize":28,"HashSizeB64":38} {"Name":"SHA-256","Genus":"SHA2","Family":"SHA","Use":"hsh","Hash":"SHA-256","HashSize":32,"HashSizeB64":43} {"Name":"SHA-384","Genus":"SHA2","Family":"SHA","Use":"hsh","Hash":"SHA-384","HashSize":48,"HashSizeB64":64} {"Name":"SHA-512","Genus":"SHA2","Family":"SHA","Use":"hsh","Hash":"SHA-512","HashSize":64,"HashSizeB64":86} {"Name":"SHA3-224","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHA3-224","HashSize":28,"HashSizeB64":38} {"Name":"SHA3-256","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHA3-256","HashSize":32,"HashSizeB64":43} {"Name":"SHA3-384","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHA3-384","HashSize":48,"HashSizeB64":64} {"Name":"SHA3-512","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHA3-512","HashSize":64,"HashSizeB64":86} {"Name":"SHAKE128","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHAKE128","HashSize":32,"HashSizeB64":43} {"Name":"SHAKE256","Genus":"SHA3","Family":"SHA","Use":"hsh","Hash":"SHAKE256","HashSize":64,"HashSizeB64":86}
func (*Alg) Parse ¶ added in v0.0.1
Example ¶
algs := []string{ "", "foo", "UnknownAlg", "UnknownSigAlg", "ES224", "ES256", "ES384", "ES512", "Ed25519", "Ed25519ph", "Ed448", "UnknownEncAlg", "UnknownHshAlg", "SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHAKE128", "SHAKE256", } var a Alg for _, alg := range algs { a.Parse(alg) // Call as method fmt.Println(a) }
Output: UnknownAlg UnknownAlg UnknownAlg UnknownSigAlg ES224 ES256 ES384 ES512 Ed25519 Ed25519ph Ed448 UnknownEncAlg UnknownHshAlg SHA-224 SHA-256 SHA-384 SHA-512 SHA3-224 SHA3-256 SHA3-384 SHA3-512 SHAKE128 SHAKE256
type B64 ¶ added in v0.0.1
type B64 []byte
Type B64 is a Coze addition to Go's base64. B64 is useful for marshaling and unmarshalling structs. B64's underlying type is []byte and is represented in JSON as "RFC 4648 base 64 URI canonical with padding truncated" (b64ut).
When converting integers or other types to B64, `nil` is encoded as "" and zero is encoded as "AA".
Example (MarshalJSON) ¶
h := B64([]byte{0, 255}) b, err := h.MarshalJSON() if err != nil { panic(err) } fmt.Println(string(b))
Output: "AP8"
Example (Non_strict_decode) ¶
Demonstrates that Coze Go will error on non-canonical base 64 encoding. See https://github.com/Cyphrme/Coze/issues/18. The last three characters of example `tmb` is `hOk`, but `hOl` also decodes to the same byte value (in Hex, `84E9`) even though they are different UTF-8 values. Tool for decoding [hOk](https://convert.zamicol.com/#?inAlph=base64&in=hOk&outAlph=Hex) and [hOl](https://convert.zamicol.com/#?inAlph=base64&in=hOl&outAlph=Hex).
As an added concern, Go's base64 ignores new line and carriage return. Thankfully, JSON unmarshal does not, making Coze's interpretation of base 64 non-malleable since Coze is JSON.
// Canonical f := new(B64Struct) err := json.Unmarshal([]byte(`{"B":"hOk"}`), f) if err != nil { panic(err) } fmt.Println(f) // Non-canonical (hOk and hOl will decode to the same bytes when non-canonical // is permitted.) f2 := new(B64Struct) err = json.Unmarshal([]byte(`{"B":"hOl"}`), f2) if err != nil { // Correctly errors fmt.Println("unmarshalling error: ", err) } // Print Unicode to show that Go is interpreting the string below correctly. b1 := []byte(fmt.Sprintf(`{"B":"hOk"}`)) b2 := []byte(fmt.Sprintf("{\"B\":\"hOk\n\"}")) // Unicode U+000A is line feed. b3 := []byte(fmt.Sprintf("{\"B\":\"hOk\r\"}")) // Unicode U+000D is line feed. fmt.Printf("%U\n", b1) fmt.Printf("%U\n", b2) fmt.Printf("%U\n", b3) fb1 := new(B64Struct) err = json.Unmarshal(b1, fb1) // Will not error if err != nil { fmt.Println(err) } fb2 := new(B64Struct) err = json.Unmarshal(b2, fb2) // Correctly errors. if err != nil { fmt.Println(err) } fb3 := new(B64Struct) err = json.Unmarshal(b3, fb3) // Correctly errors. if err != nil { fmt.Println(err) }
Output: &{hOk} unmarshalling error: illegal base64 data at input byte 2 [U+007B U+0022 U+0042 U+0022 U+003A U+0022 U+0068 U+004F U+006B U+0022 U+007D] [U+007B U+0022 U+0042 U+0022 U+003A U+0022 U+0068 U+004F U+006B U+000A U+0022 U+007D] [U+007B U+0022 U+0042 U+0022 U+003A U+0022 U+0068 U+004F U+006B U+000D U+0022 U+007D] invalid character '\n' in string literal invalid character '\r' in string literal
Example (UnmarshalJSON) ¶
f := new(B64Struct) err := json.Unmarshal([]byte(`{"B":"AP8"}`), f) if err != nil { panic(err) } b, err := Marshal(f) if err != nil { panic(err) } fmt.Printf("%s,%#v\n", b, B64(b))
Output: {"B":"AP8"},eyJCIjoiQVA4In0
Example (Zero_nil) ¶
B64 of nil is "" while B64 of 0 is "AA".
var b []byte b = nil fmt.Printf("B64 string nil: `%s`\n", B64(b)) b = []byte{0} fmt.Printf("B64 string zero: `%s`\n", B64(b))
Output: B64 string nil: `` B64 string zero: `AA`
func CanonicalHash ¶ added in v0.0.1
CanonicalHash accepts []byte and optional canon and returns digest.
If input is already in canonical form, Hash() may also be called instead.
Example ¶
ExampleCanonicalHash. See also Example_genCad
canon := []string{"alg", "iat", "msg", "tmb", "typ"} cad, err := CanonicalHash([]byte(GoldenPay), canon, SHA256) if err != nil { panic(err) } fmt.Println(cad.String()) // Without canon cad, err = CanonicalHash([]byte(GoldenPay), nil, SHA256) if err != nil { panic(err) } fmt.Println(cad.String())
Output: 4bmwgjkxQJIG2jiLiqq6eKptwTs97lYAFUtS25Rc3DU Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4
Example (GenCad) ¶
See also ExampleCanonicalHash.
fmt.Println(CanonicalHash([]byte(GoldenPay), nil, GoldenKey.Alg.Hash()))
Output: Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4 <nil>
Example (InvalidAlg) ¶
Demonstrates expected behavior for invalid HshAlgs.
_, err := CanonicalHash([]byte(GoldenPay), nil, "") fmt.Println(err) _, err = CanonicalHash([]byte(GoldenPay), nil, "test") fmt.Println(err)
Output: Hash: invalid HshAlg "" Hash: invalid HshAlg "test"
Example (Permutations) ¶
Example CanonicalHash for all hashing algos.
canon := []string{"alg", "iat", "msg", "tmb", "typ"} algs := []string{"SHA-224", "SHA-256", "SHA-384", "SHA-512", "SHA3-224", "SHA3-256", "SHA3-384", "SHA3-512", "SHAKE128", "SHAKE256"} for _, alg := range algs { cad, err := CanonicalHash([]byte(GoldenPay), canon, ParseHashAlg(alg)) if err != nil { panic(err) } fmt.Println(cad.String()) }
Output: cGCQ6FHj0fjAyYbvxS_8sfC0qTaSLJtcu0Xkhw 4bmwgjkxQJIG2jiLiqq6eKptwTs97lYAFUtS25Rc3DU WQiyyY5Ye2Y8vKcbANlmiXJkU-SVEgboYJg-wnrOKJ3v8PcI5XvQu_-C4yyGFrbW irByY6uGnp6DrPvInvggL0ibo2p5yNvcuMVx1GiZoOArVIp4cGkAfB2FvknV5DyzKMHH-tV6vW8TyW7LZOyVFw 9YyKIbtFYbSNqdwAXcwV0lwLb-X65k6zTBTWeQ 8P9aSEJjC8tRKzfLNYBQTTXK-9E-DPlNaH_ikFkYUHQ suqhBt29HS7c_wwDpcp943h0HlSI_FQdOkiz-Tjf9R_Wegil2pXHVxIFXkpOaceP dAzMJWHLnGw9kjeo4RbVhzAAL6bwGasQbLFLZ1kHhdhGNNQm5nMib0cAQAAoIwdnKf0L8RADELg1XSFd8aJKww QzbJ9ONj21KF3Zno1ctdIHfpGqmFGm11tinsAJUkYOg MFYCTNhmavKZmFk_JNcttN9ccm4MAuYN3T868B2q0olpJ_6po2l98-617RfjnxkVuY2J--JjKt-KGi1S2RL4Bw
func Decode ¶ added in v0.0.1
Decode decodes a b64ut string.
Example ¶
b, err := Decode(GoldenTmb) if err != nil { panic(err) } fmt.Println(b)
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk
func Hash ¶ added in v0.0.1
Hash hashes msg and returns the digest. Returns nil on error. Errors on invalid HshAlg or if the resulting digest is empty (as a sanity check).
For algorithms that support arbitrary sized digests, Hash only returns a static size. (SHAKE128 returns 32 bytes and SHAKE256 returns 64 bytes.)
func MustDecode ¶ added in v0.0.1
MustDecode decodes b64ut and panics on error.
Example ¶
fmt.Println(MustDecode(GoldenTmb))
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk
func PadInts ¶ added in v0.0.1
PadInts creates a big-endian byte slice with given size that is the left padded concatenation of two input integers. Parameter `size` must be even. From Go's packages, X, Y, R, and S are type big.Int of varying size. Before encoding to fixed size string, left padding of bytes is needed.
Algorithm notes: EdDSA is little-endian while ECDSA is big-endian. EdDSA should not be used with this function.
For ECDSA, Coze's `x` and `sig` is left padded concatenation of X || Y and R || S respectively.
Note: ES512's signature size is 132 bytes (and not 128, 131, or 130.25), because R and S are each respectively rounded up and padded to 528 and for a total signature size of 1056 bits. See https://datatracker.ietf.org/doc/html/rfc4754#section-7
func Thumbprint ¶
Thumbprint generates `tmb` which is the digest of canon [alg, x]. X must be set and be a valid length. On error, tmb is set to nil.
Example ¶
fmt.Println(Thumbprint(&GoldenKey))
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk <nil>
func (B64) GoString ¶ added in v0.0.1
GoString implements fmt.GoStringer. Use with `%#v` (not %s or %+v).
func (B64) MarshalJSON ¶ added in v0.0.1
MarshalJSON implements json.Marshaler. Error is always nil.
func (*B64) UnmarshalJSON ¶ added in v0.0.1
UnmarshalJSON implements json.Unmarshaler.
type Coze ¶ added in v0.0.1
type Coze struct { Pay json.RawMessage `json:"pay,omitempty"` Key *Key `json:"key,omitempty"` Can []string `json:"can,omitempty"` Cad B64 `json:"cad,omitempty"` Sig B64 `json:"sig,omitempty"` Czd B64 `json:"czd,omitempty"` Parsed *Pay `json:"-"` }
Coze is for signed Coze objects (cozies). See the Coze docs (README.md) for more on the construction of `coze`.
Pay: The raw Payload. Key: Key used to sign the message. Must be pointer, otherwise json.Marshal will not marshal on zero type. See: https://github.com/golang/go/issues/11939. Can: "Canon" Pay's fields in order of appearance. Cad: "Canonical Digest" Pay's compactified form digest. Sig: Signature over `cad`. Czd: "Coze digest" with canon ["cad","sig"]. Parsed: The standard Coze pay fields ["alg","iat","tmb","typ"] parsed from `Pay`. `Parsed` is populated by Meta() and is JSON ignored.
Example (Embed) ¶
ExampleCoze_embed demonstrates how to embed a JSON `coze` into a third party JSON structure.
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } type Outer struct { Name string `json:"name"` Coze Coze `json:"coze"` // Embed a Coze into a larger, application defined JSON structure. } b, _ := json.Marshal(Outer{Name: "Bob", Coze: *cz}) fmt.Printf("%s", b)
Output: {"name":"Bob","coze":{"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w"}}
Example (JsonMarshal) ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } b, err := Marshal(cz) if err != nil { panic(err) } fmt.Printf("%+s\n", b)
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w"}
Example (JsonMarshalPretty) ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } b, err := MarshalPretty(cz) if err != nil { panic(err) } fmt.Printf("%+s\n", b)
Output: { "pay": { "msg": "Coze Rocks", "alg": "ES256", "iat": 1623132000, "tmb": "cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk", "typ": "cyphr.me/msg" }, "sig": "Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w" }
Example (JsonUnmarshal) ¶
ExampleCoze_jsonUnmarshal tests unmarshalling a coze.
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } // remarshal for comparison b, err := Marshal(cz) if err != nil { panic(err) } fmt.Println(string(b))
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w"}
func (*Coze) Meta ¶ added in v0.0.1
Meta calculates [can, cad, czd] and sets Coze.Parsed ["alg","iat","tmb","typ"] from Pay. Coze.Pay, Coze.Pay.Alg, and Coze.Sig must be set. Meta resets Parsed ("alg","iat","tmb","typ") to zero before populating Parsed from Pay. If needing to use for contextual cozies, use "MetaWithAlg".
Meta does no cryptographic verification.
Example ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } err = cz.Meta() if err != nil { panic(err) } fmt.Printf("%s\n", cz)
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","alg","iat","tmb","typ"],"cad":"Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4","sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w","czd":"TnRe4DRuGJlw280u3pGhMDOIYM7ii7J8_PhNuSScsIU"}
func (*Coze) MetaWithAlg ¶ added in v0.0.1
MetaWithAlg is for contextual cozies that may be lacking `alg` in `pay`, but `alg` in otherwise known. MetaWithAlg recalculates [can, cad, czd] and sets Coze.Parsed ("alg","iat","tmb","typ") from Pay. Does not calculate `czd` if Coze.Sig is empty.
Errors on 1. Invalid JSON. 2. No alg is given. (both coze.pay.alg and alg are empty). 3. Mismatched Pay.Alg and parameter alg if both are set.
MetaWithAlg does no cryptographic verification.
Example ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } // coze.pay.alg given and parameter alg given. err = cz.MetaWithAlg(SEAlg(ES256)) if err != nil { panic(err) } fmt.Printf("%s\n", cz) // coze.pay.alg given and parameter alg not given. (Alg is parsed from pay). err = cz.MetaWithAlg("") if err != nil { panic(err) } fmt.Printf("%s\n", cz) // Test mismatch alg, which must error. err = cz.MetaWithAlg(SEAlg(ES224)) if err == nil { fmt.Println("Test must error") } // Test no coze.pay.alg or alg given, which must error. cz2 := new(Coze) err = json.Unmarshal(GoldenCozeNoAlg, cz2) if err != nil { panic(err) } err = cz2.Meta() if err == nil { fmt.Println("Test must error") } // Test no coze.pay.alg but alg is given (contextual coze) err = cz2.MetaWithAlg(SEAlg(ES256)) if err != nil { panic(err) } fmt.Printf("%s\n", cz2) // Test no coze.pay.alg or coze.sig, so czd should not be calculated cz3 := new(Coze) err = json.Unmarshal(GoldenPayNoAlg, &cz3.Pay) if err != nil { panic(err) } err = cz3.MetaWithAlg(SEAlg(ES256)) if err != nil { panic(err) } fmt.Printf("%s\n", cz3)
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","alg","iat","tmb","typ"],"cad":"Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4","sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w","czd":"TnRe4DRuGJlw280u3pGhMDOIYM7ii7J8_PhNuSScsIU"} {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","alg","iat","tmb","typ"],"cad":"Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4","sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w","czd":"TnRe4DRuGJlw280u3pGhMDOIYM7ii7J8_PhNuSScsIU"} {"pay":{"msg":"Coze Rocks","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","iat","tmb","typ"],"cad":"K6MVyIFqhBhLvNafZ8sMCRpCqR1oeFpowi7j8P1uE0M","sig":"reOiKUO--OwgTNlYpKN60_gZARnW5X6PmQw4zWYbz2QryetRg_qS4KvwEVe1aiSAsWlkVA3MqYuaIM5ihY_8NQ","czd":"g6kRqHesiST6L38eZPcTk4Bq-fCxtbD6jTvRS8LKMv8"} {"pay":{"msg":"Coze Rocks","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","iat","tmb","typ"],"cad":"K6MVyIFqhBhLvNafZ8sMCRpCqR1oeFpowi7j8P1uE0M"}
Example (Contextual) ¶
// Test MetaWithAlg using no sig, which should calc what it can. cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } cz.Sig = []byte{} // set sig to nothing. err = cz.MetaWithAlg("") if err != nil { panic(err) } fmt.Printf("%s\n", cz) // Empty coze with coze.parsed.alg cz = new(Coze) err = json.Unmarshal(GoldenCozeEmpty, cz) if err != nil { panic(err) } err = cz.MetaWithAlg(GoldenKey.Alg) if err != nil { panic(err) } fmt.Printf("%s\n", cz)
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"can":["msg","alg","iat","tmb","typ"],"cad":"Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4"} {"pay":{},"cad":"RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o","sig":"9iesKUSV7L1-xz5yd3A94vCkKLmdOAnrcPXTU3_qeKRRbHuy5EvMMFNRkW_sNLo-vvEPO9BmeUkcNh-ok18I_A","czd":"zU7xRwp8XU_VmdOLNBlMBualhoyHiM_cGhib6LPwWlc"}
func (Coze) String ¶ added in v0.0.1
String implements fmt.Stringer. Without this method `pay` prints as bytes. On error, returns the error as a string.
Example ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } fmt.Println(cz)
Output: {"pay":{"msg":"Coze Rocks","alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"},"sig":"Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w"}
func (*Coze) UnmarshalJSON ¶ added in v0.0.1
UnmarshalJSON unmarshals checks for duplicates and unmarshals `coze`. See notes on Pay.UnmarshalJSON.
Example (Duplicate) ¶
Example demonstrating that unmarshalling a `coze` that has duplicate field names results in an error.
h := &Pay{} msg := []byte(`{"coze":{"pay":"ES256","pay":"ES384"}}`) err := json.Unmarshal(msg, h) fmt.Println(err)
Output: Coze: JSON duplicate field "pay"
type Crv ¶ added in v0.0.1
type Crv string // Curve type. Used for EC curves.
func (Crv) EllipticCurve ¶ added in v0.0.1
Curve returns Go's elliptic.Curve for the given crv. Returns nil if there is no matching `elliptic.Curve`.
type ErrJSONDuplicate ¶ added in v0.0.3
type ErrJSONDuplicate error
ErrJSONDuplicate allows applications to check for JSON duplicate error.
type HshAlg ¶ added in v0.0.3
type HshAlg Alg // Hashing Algorithm
Example (JsonMarshal) ¶
type testStruct = struct { H HshAlg `json:"hshAlg"` } z := testStruct{H: SHA256} jm, err := Marshal(z) if err != nil { panic(err) } fmt.Printf("%+s\n", jm)
Output: {"hshAlg":"SHA-256"}
Example (Print) ¶
h := SHA256 fmt.Println(h)
Output: SHA-256
func ParseHashAlg ¶ added in v0.0.1
func (HshAlg) Size ¶ added in v0.0.3
HashSize returns the digest size in bytes for the given hashing algorithm.
For SHAKE128 and SHAKE256, this function returns the static sizes, 32 and 64 respectively, although the algorithm permits any larger arbitrary output size. SHAKE128 has 128 bits of pre-collision resistance and a capacity of 256, although it has arbitrary output size. SHAKE256 has 256 bits of pre-collision resistance and a capacity of 512, although it has arbitrary output size.
type Key ¶ added in v0.0.1
type Key struct { Alg SEAlg `json:"alg,omitempty"` D B64 `json:"d,omitempty"` Iat int64 `json:"iat,omitempty"` Kid string `json:"kid,omitempty"` Rvk int64 `json:"rvk,omitempty"` Tmb B64 `json:"tmb,omitempty"` Typ string `json:"typ,omitempty"` X B64 `json:"x,omitempty"` }
Key is a Coze key. See `README.md` for details on Coze key. Fields `alg` and `tmb` must be in correct relative order for thumbprint canon because JSON marshal uses struct order.
Standard Coze key Fields
`alg` - Specific key algorithm. E.g. "ES256" or "Ed25519". `d` - Private component. E.g. "bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA". `iat` - Unix time of when the key was created. E.g. 1626069600. `kid` - Human readable, non-programmatic label. E.g. "My Coze key". `rvk` - Unix time of key revocation. See docs on `rvk`. E.g. 1626069601. `tmb` - Key thumbprint. E.g. "cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk". `typ` - Application label for key. E.g. "coze/key". `x` - Public component. E.g. "2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g".
Example (JsonMarshal) ¶
b, err := Marshal(GoldenKey) if err != nil { panic(err) } fmt.Printf("%s\n", string(b))
Output: {"alg":"ES256","d":"bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA","iat":1623132000,"kid":"Zami's Majuscule Key.","tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g"}
Example (JsonUnmarshal) ¶
ExampleKey_jsonUnmarshal tests unmarshalling a Coze key.
Key := new(Key) err := json.Unmarshal([]byte(GoldenKeyString), Key) if err != nil { panic(err) } fmt.Printf("%+v\n", Key)
Output: {"alg":"ES256","d":"bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA","iat":1623132000,"kid":"Zami's Majuscule Key.","tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g"}
Example (Unmarshal) ¶
Example demonstrating that unmarshal generates `tmb` from x,
var GoldenPukNoTmb = json.RawMessage(`{ "alg":"ES256", "iat":1623132000, "kid":"Zami's Majuscule Key.", "x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g" }`) czk := new(Key) err := json.Unmarshal(GoldenPukNoTmb, czk) if err != nil { panic(err) } fmt.Println(czk)
Output: {"alg":"ES256","iat":1623132000,"kid":"Zami's Majuscule Key.","tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g"}
func NewKey ¶
NewKey generates a new Coze key.
Example ¶
algs := []SigAlg{ ES224, ES256, ES384, ES512, Ed25519, } for _, alg := range algs { Key, err := NewKey(SEAlg(alg)) if err != nil { panic(err) } fmt.Printf("%s, %t\n", Key.Alg, Key.Valid()) }
Output: ES224, true ES256, true ES384, true ES512, true Ed25519, true
Example (Bad) ¶
fmt.Println(NewKey(SEAlg(SHA256))) // Invalid signing alg, fails.
Output: <nil> NewKey: unsupported alg "SHA-256"
Example (Valid) ¶
ck, err := NewKey(SEAlg(ES256)) if err != nil { panic(err) } fmt.Println(ck.Valid())
Output: true
func (*Key) Correct ¶ added in v0.0.1
Correct is an advanced function for checking for the correct construction of a Coze key if it can be known from the given inputs. Key must have at least one of [`tmb`, `x`,`d`] and `alg` set. Correct may return no error on cryptographically invalid public keys. Using input information, if possible to definitively know the given key is incorrect, Correct returns an error, but if plausibly correct, Correct returns no error. Correct answers the question: "Is the given Coze key reasonable using the information provided?". Correct is useful for sanity checking public keys without signed messages, sanity checking `tmb` only keys, and validating private keys. Use function "Verify" instead for verifying public keys when a signed message is available. Correct is considered an advanced function. Please understand it thoroughly before use.
Correct:
- Checks the length of `x` and/or `tmb` against `alg`.
- If `x` and `tmb` are present, verifies correct `tmb`.
- If `d` is present, verifies correct `tmb` and `x` if present, and verifies the key by verifying a generated signature.
- If possible, sets tmb and/or x.
Functions that call correct can check for correctness by `if key.Correct() != nil`
Example ¶
ExampleKey_Correct demonstrates the expectations from Correct() when different key fields appear. Note that some calls to Correct() pass on _invalid_ keys depending on given fields.
// helper print function tf := func(err ...error) { for i, e := range err { if e != nil { fmt.Printf("%t", false) } else { fmt.Printf("%t", true) } if i < len(err)-1 { fmt.Printf(", ") } } } keys := []Key{GoldenKeyBadD, GoldenKeyBadX, GoldenKey} // Test new keys. These keys should pass every test. algs := []string{"ES224", "ES256", "ES384", "ES512", "Ed25519"} for _, alg := range algs { key, err := NewKey(SEAlg(Parse(alg))) if err != nil { panic(err) } keys = append(keys, *key) } for _, k := range keys { gk2 := k // Make a copy // Key with with [alg,d,tmb,x] p1 := gk2.Correct() // A key with [alg,tmb,d] gk2 = k gk2.X = []byte{} p2 := gk2.Correct() // Key with [alg,d]. gk2 = k gk2.X = []byte{} gk2.Tmb = []byte{} p3 := gk2.Correct() // A key with [alg,x,d]. gk2 = k gk2.Tmb = []byte{} p4 := gk2.Correct() // A key with [alg,x,tmb] gk2 = k gk2.D = []byte{} p5 := gk2.Correct() // Key with [alg,tmb] gk2 = k gk2.D = []byte{} gk2.X = []byte{} p6 := gk2.Correct() tf(p1, p2, p3, p4, p5, p6) fmt.Printf("\n") }
Output: false, false, true, false, true, true false, false, true, false, false, true true, true, true, true, true, true true, true, true, true, true, true true, true, true, true, true, true true, true, true, true, true, true true, true, true, true, true, true true, true, true, true, true, true
func (Key) IsRevoked ¶ added in v0.0.1
IsRevoked returns true if the given Key is marked as revoked.
Example ¶
gk2 := GoldenKey // Make a copy fmt.Println(gk2.IsRevoked()) coze, err := gk2.Revoke() if err != nil { panic(err) } pay := new(Pay) err = pay.UnmarshalJSON(coze.Pay) if err != nil { panic(err) } // Both the revoke coze and the key should be interpreted as revoked. fmt.Println(pay.IsRevoke()) fmt.Println(gk2.IsRevoked())
Output: false true true
func (*Key) Revoke ¶ added in v0.0.1
Revoke returns a signed revoke coze and sets `rvk` on the key itself.
func (*Key) Sign ¶ added in v0.0.1
Sign uses a private Coze key to sign a digest.
Sign() and Verify() do not check if the Coze is correct, such as checking pay.alg and pay.tmb matches with Key. Use SignPay, SignCoze, SignPayJSON, and/or VerifyCoze if needing Coze validation.
Example ¶
// Manual signing of empty Coze, `{"pay":{},"sig":"9iesKU..."}`, is a valid // Coze. In this case, it would be better to use SignPayJSON. d, err := Hash(GoldenKey.Alg.Hash(), []byte("{}")) if err != nil { panic(err) } sig, err := GoldenKey.Sign(d) if err != nil { panic(err) } fmt.Println(GoldenKey.Verify(d, sig)) // Signing a previously known cad. cad := MustDecode(GoldenCad) sig, err = GoldenKey.Sign(cad) if err != nil { panic(err) } fmt.Printf("%v\n", GoldenKey.Verify(cad, sig))
Output: true true
func (*Key) SignCoze ¶ added in v0.0.1
SignCoze signs `coze.pay` and sets `coze.sig`. See documentation on SignPay.
Example ¶
cz := new(Coze) cz.Pay = json.RawMessage(GoldenPay) err := GoldenKey.SignCoze(cz) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(cz))
Output: true <nil>
func (*Key) SignPay ¶ added in v0.0.1
SignPay signs coze.Pay and returns a new Coze with coze.Sig populated. If set, SignPay checks that `pay.alg` and `key.alg` match and that `pay.tmb` is correct according to `key`.
SignPay works with contextual cozies that lack pay.alg and/or pay.tmb and uses key as a source of truth.
Example ¶
ExampleKey_SignPay demonstrates converting a custom data structure into a coze, signing it, and verifying the results.
customStruct := CustomStruct{ Msg: "Coze Rocks", } pay := Pay{ Alg: SEAlg(ES256), Iat: 1623132000, // Static for demonstration. Use time.Now().Unix(). Tmb: MustDecode("cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk"), Typ: "cyphr.me/msg", Struct: customStruct, } coze, err := GoldenKey.SignPay(&pay) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(coze))
Output: true <nil>
func (*Key) SignPayJSON ¶ added in v0.0.1
func (c *Key) SignPayJSON(pay json.RawMessage) (coze *Coze, err error)
SignPayJSON signs a json `coze.pay`. See documentation on SignPay.
Example ¶
coze, err := GoldenKey.SignPayJSON(json.RawMessage(GoldenPay)) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(coze))
Output: true <nil>
Example (Empty) ¶
ExampleKey_Sign_empty demonstrates signing of empty Coze, `{"pay":{},"sig":"9iesKU..."}`, is valid.
coze, err := GoldenKey.SignPayJSON([]byte("{}")) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(coze))
Output: true <nil>
func (Key) String ¶ added in v0.0.1
String implements Stringer. Returns empty on error.
Example ¶
fmt.Printf("%s\n", GoldenKey)
Output: {"alg":"ES256","d":"bNstg4_H3m3SlROufwRSEgibLrBuRq9114OvdapcpVA","iat":1623132000,"kid":"Zami's Majuscule Key.","tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g"}
func (*Key) Thumbprint ¶ added in v0.0.1
Thumbprint generates `tmb` which is the digest of canon [alg, x]. X must be set and be a valid length. On error, tmb is set to nil.
Example ¶
gk2 := GoldenKey // Make a copy. gk2.Tmb = []byte{} // Set to empty to ensure recalculation. err := gk2.Thumbprint() fmt.Println(gk2.Tmb, err)
Output: cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk <nil>
func (*Key) ToPubEcdsa ¶ added in v0.0.4
KeyToPubEcdsa converts a Coze Key to ecdsa.PublicKey.
func (*Key) UnmarshalJSON ¶ added in v0.0.4
UnmarshalJSON always populates `tmb` even if it isn't given.
Example (Duplicate) ¶
Example demonstrating that unmarshalling a `pay` that has duplicate field names results in an error.
k := &Key{} msg := []byte(`{"alg":"ES256","alg":"ES256"}`) err := json.Unmarshal(msg, k) fmt.Println(err)
Output: Coze: JSON duplicate field "alg"
func (*Key) Valid ¶ added in v0.0.1
Valid cryptographically validates a private Coze Key by signing a message and verifying the resulting signature with the given "x".
Valid always returns false on public keys. Use function "Verify" for public keys with signed message. See also function Correct.
Example ¶
Tests valid on a good Coze key and a bad Coze key
fmt.Println(GoldenKey.Valid(), GoldenKeyBadD.Valid())
Output: true false
func (*Key) Verify ¶ added in v0.0.1
Verify uses a Coze key to verify a digest. Typically digest is `cad`.
Sign() and Verify() do not check if the coze is correct, such as checking pay.alg and pay.tmb matches with Key. Use SignPay, SignCoze, SignPayJSON, and/or VerifyCoze if needing Coze validation.
Example ¶
fmt.Println(GoldenKey.Verify(MustDecode(GoldenCad), MustDecode(GoldenSig)))
Output: true
Example (Empty) ¶
Example demonstrating the verification of the empty coze from the README.
cz := new(Coze) err := json.Unmarshal(GoldenCozeEmpty, cz) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(cz))
Output: true <nil>
func (*Key) VerifyCoze ¶ added in v0.0.1
VerifyCoze cryptographically verifies `pay` with given `sig`. If set VerifyCoze checks that `pay.alg` and `key.alg` match and that `pay.tmb` is correct according to `key`. Always returns false on error.
VerifyCoze works with contextual cozies that lack pay.alg and/or pay.tmb and uses key as a source of truth.
Example ¶
cz := new(Coze) err := json.Unmarshal([]byte(GoldenCoze), cz) if err != nil { panic(err) } fmt.Println(GoldenKey.VerifyCoze(cz))
Output: true <nil>
type Marshaler ¶ added in v0.0.1
Marshaler is a UTF-8 marshaller for Go structs. Go's `json.Marshal` removes the valid characters "&". "<", ">". See note on Marshal. (Note that Marshaler follows the Go "-er" convention for interfaces while marshaller is spelled with two l's)
type Params ¶ added in v0.0.1
type Params struct { Name string Genus GenAlg `json:"Genus"` Family FamAlg `json:"Family"` Use Use `json:"Use,omitempty"` Hash HshAlg `json:"Hash,omitempty"` // Hash HashSize int `json:"HashSize,omitempty"` HashSizeB64 int `json:"HashSizeB64,omitempty"` XSize int `json:"XSize,omitempty"` // Key XSizeB64 int `json:"XSizeB64,omitempty"` DSize int `json:"DSize,omitempty"` DSizeB64 int `json:"DSizeB64,omitempty"` Curve Crv `json:"Curve,omitempty"` SigSize int `json:"SigSize,omitempty"` // Sig SigSizeB64 int `json:"SigSizeB64,omitempty"` }
Params reports all relevant parameters for an `alg`. If a parameter is not applicable for a particular `alg`, its value is be populated with the Go zero value, e.g. for the hash alg "SHA-256" Curve's value is 0 and omitted from JSON marshaling.
type Pay ¶ added in v0.0.1
type Pay struct { Alg SEAlg `json:"alg,omitempty"` // e.g. "ES256" Iat int64 `json:"iat,omitempty"` // e.g. 1623132000 Tmb B64 `json:"tmb,omitempty"` // e.g. "cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk" Typ string `json:"typ,omitempty"` // e.g. "cyphr.me/msg/create" // Rvk is only for revoke messages. Rvk int64 `json:"rvk,omitempty"` // e.g. 1623132000 // Custom arbitrary struct given by application. Struct any `json:"-"` }
Pay contains the standard Coze pay fields as well as custom struct given by third party applications. This allows embedding third party structs into Pay for creating custom cozies (see example ExampleKey_SignPay).
The JSON tags on [Alg, Iat, Tmb, Typ, Rvk, Struct] are ineffective due to the custom MarshalJSON(), however they are present for documentation.
`Struct` will be marshaled when not empty. The custom marshaller promotes fields inside `Struct` to be top level fields inside of `pay`. The tag `json:"-"` is ignored by the custom marshaller, and is set to "-" so that the default marshaller does not include it.
iat and rvk are type int64 and not uint64 to follow the advised type for third party time fields.
Example (Embedded) ¶
// Example custom struct. type User struct { DisplayName string FirstName string LastName string Email string `json:",omitempty"` // Example of non-required field. } user := User{ DisplayName: "Coze", FirstName: "Foo", LastName: "Bar", } // Example of converting a custom struct to a coze. pay := Pay{ Alg: GoldenKey.Alg, Tmb: GoldenKey.Tmb, Struct: &user, } coze, err := GoldenKey.SignPay(&pay) if err != nil { panic(err) } v, err := GoldenKey.VerifyCoze(coze) if err != nil { panic(err) } // Set sig to nil for deterministic printout coze.Sig = nil fmt.Println(v) fmt.Printf("%+v\n", coze)
Output: true {"pay":{"alg":"ES256","tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","DisplayName":"Coze","FirstName":"Foo","LastName":"Bar"}}
Example (JsonMarshalCustom) ¶
ExamplePay_jsonMarshalCustom demonstrates marshalling Pay with a custom structure.
customStruct := CustomStruct{ Msg: "Coze Rocks", } inputPay := Pay{ Alg: SEAlg(ES256), Iat: 1623132000, // Static for demonstration. Use time.Now().Unix(). Tmb: MustDecode("cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk"), Typ: "cyphr.me/msg", Struct: customStruct, } // May also call inputPay.MarshalJSON() or Marshal(&inputPay) instead. s, err := Marshal(&inputPay) if err != nil { panic(err) } fmt.Println(string(s))
Output: {"alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg","msg":"Coze Rocks"}
Example (JsonUnmarshal) ¶
ExamplePay_jsonUnmarshal tests unmarshalling a Pay.
h := &Pay{} err := json.Unmarshal([]byte(GoldenPay), h) if err != nil { panic(err) } out, err := Marshal(h) if err != nil { panic(err) } fmt.Printf("%s\n", out)
Output: {"alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"}
Example (JsonUnmarshalCustom) ¶
ExamplePay_jsonUnmarshalCustom demonstrates unmarshalling Pay with a custom structure.
pay := new(Pay) var emptyCustomStruct CustomStruct pay.Struct = &emptyCustomStruct err := json.Unmarshal([]byte(GoldenPay), &pay) if err != nil { fmt.Printf("Unmarshal error: %s\n", err) } fmt.Println(pay) fmt.Println(pay.Struct)
Output: {"alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg","msg":"Coze Rocks"} &{Coze Rocks}
Example (JsonUnmarshalCustomManual) ¶
ExamplePay_jsonUnmarshalCustomManual demonstrates "manually" unmarshalling Pay with a custom structure.
var pay Pay err := json.Unmarshal([]byte(GoldenPay), &pay) if err != nil { panic(err) } fmt.Println(pay) var custom CustomStruct err = json.Unmarshal([]byte(GoldenPay), &custom) if err != nil { panic(err) } fmt.Println(custom)
Output: {"alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg"} {Coze Rocks}
func (*Pay) MarshalJSON ¶ added in v0.0.1
MarshalJSON promotes the embedded field "Struct" to top level JSON. Solution from Jonathan Hall: https://jhall.io/posts/go-json-tricks-embedded-marshaler
func (Pay) String ¶ added in v0.0.1
String implements fmt.Stringer. On error, returns the error as a string.
Example (Custom) ¶
ExamplePay_String_custom demonstrates fmt.Stringer on Pay with a custom structure.
customStruct := CustomStruct{ Msg: "Coze Rocks", } inputPay := Pay{ Alg: SEAlg(ES256), Iat: 1623132000, // Static for demonstration. Use time.Now().Unix(). Tmb: MustDecode("cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk"), Typ: "cyphr.me/msg", Struct: customStruct, } fmt.Println(inputPay)
Output: {"alg":"ES256","iat":1623132000,"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk","typ":"cyphr.me/msg","msg":"Coze Rocks"}
func (*Pay) UnmarshalJSON ¶ added in v0.0.1
UnmarshalJSON unmarshals both Pay and if given custom Pay.Struct. Throws an error on duplicate. (Duplicate related, see https://github.com/golang/go/issues/48298)
Example (Duplicate) ¶
Example demonstrating that unmarshalling a `pay` that has duplicate field names results in an error.
h := &Pay{} msg := []byte(`{"alg":"ES256","alg":"ES384"}`) err := json.Unmarshal(msg, h) fmt.Println(err)
Output: Coze: JSON duplicate field "alg"
type SB64 ¶ added in v0.0.6
type SB64 string
SB64 is useful for B64 map keys. Idiomatically, map key type should be `B64`, but currently in Go map keys are only type `string`, not `[]byte`. Since B64's underlying type is `[]byte` it cannot be used as a map key. See https://github.com/golang/go/issues/283 and https://github.com/google/go-cmp/issues/67. SB64 will be deprecated if/when Go supports []byte keys.
This is an acceptable hack because (from https://go.dev/blog/strings)
>[A] string holds arbitrary bytes. It is not required to hold Unicode text, > UTF-8 text, or any other predefined format. As far as the content of a > string is concerned, it is exactly equivalent to a slice of bytes.
Example ¶
ExampleSB64 demonstrates using SB64 as a map key and that fmt prints "RFC 4648 base 64 URI canonical with padding truncated" properly.
b := MustDecode("zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0") b2 := MustDecode("vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA") lp := make(map[SB64]B64) lp[SB64(b)] = B64(b2) fmt.Printf("%s\n", SB64(b)) fmt.Printf("%s\n", lp) fmt.Printf("%+v\n", lp) fmt.Printf("%#v\n", lp)
Output: zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0 map[zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA] map[zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA] map[coze.SB64]coze.B64{zVzgRU3WFpnrlVJAnI4ZU1Od4Agl5Zd4jIP79oubOW0:vZIAk8rjcSIKZKokGylCtVoI3DXvFYJn4XNWzf_C_FA}
type SEAlg ¶ added in v0.0.1
type SEAlg Alg
SEAlg is the Signing or Encryption alg. Super type of SigAlg and EncAlg and is itself not a specific algorithm and is not included in `Alg`. It is useful for algorithms that need `x` and/or `d` and related functions.
const (
SEAlgUnknown SEAlg = "UnknownSEAlg"
)
func (SEAlg) DSize ¶ added in v0.0.1
DSize returns the byte size of `d`. Returns 0 on invalid algorithm.
type SigAlg ¶ added in v0.0.1
type SigAlg SEAlg // Signing Algorithm