Skip to content

Commit

Permalink
Merge pull request #20 from Cyphrme/orderedmap
Browse files Browse the repository at this point in the history
Orderedmap
  • Loading branch information
zamicol authored Jul 10, 2023
2 parents 60ffd34 + a601a83 commit 76f019b
Show file tree
Hide file tree
Showing 14 changed files with 984 additions and 311 deletions.
26 changes: 26 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright Cypherpunk LLC (Cyphr.me) and contributors

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ readability.
4. Provide defined cipher suites.

### Coze Fields
Coze JSON fields are case sensitive and unique. Coze defines standard fields
and applications may include additional fields as desired. All fields are
Coze defines standard fields and applications may include additional fields as
desired. Coze JSON fields are case sensitive and unique. All fields are
optional, but omitting standard fields may limit compatibility. Binary values
are encoded as [RFC 4648 base 64 URI canonical with padding truncated][RFC4648]
(b64ut). The Coze objects `pay`, `key`, and `coze` have respective standard
fields.
fields. Unmarshalling JSON with duplicate fields must error.

#### All Coze Standard Fields
![Coze Standard Fields](docs/img/coze_standard_fields.png)
Expand Down Expand Up @@ -100,7 +100,7 @@ programmatically.


## Coze object
The JSON name `coze` may be used to wrap Coze objects. For example:
The JSON name `coze` may be used to wrap Coze objects.

```JSON
{
Expand Down Expand Up @@ -163,7 +163,7 @@ A tautologic coze:
"tmb":"cLj8vsYtMBwYkzoFVZHBZo6SNL8wSdCIjCKAwXNuhOk",
"x":"2nTOaFVm2QLxmUO_SjgyscVHBtvHEfo2rq65MvgNRjORojq39Haq9rXNxvXxwba_Xj0F5vZibJR3isBdOWbo5g"
},
"can": ["alg","iat","msg","tmb","typ"],
"can": ["msg","alg","iat","tmb","typ"],
"cad": "Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4",
"czd": "TnRe4DRuGJlw280u3pGhMDOIYM7ii7J8_PhNuSScsIU",
"sig": "Jl8Kt4nznAf0LGgO5yn_9HkGdY3ulvjg-NyRGzlmJzhncbTkFFn9jrwIwGoRAQYhjc88wmwFNH5u_rO56USo_w"
Expand Down
90 changes: 45 additions & 45 deletions alg.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,53 +80,53 @@ type (
////////////////

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"
UnknownHashAlg HshAlg = "UnknownHashAlg"
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"
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"
)

// Algs includes all algs, including
// unknown algs, SigAlg, EncAlg, and HshAlg.
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(UnknownHashAlg): Alg(UnknownHashAlg),
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),
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),
}

var algs []string = maps.Keys(Algs)
Expand All @@ -153,7 +153,7 @@ var EncAlgs = []EncAlg{

// Hash algs.
var HshAlgs = []HshAlg{
UnknownHashAlg,
UnknownHshAlg,
SHA224,
SHA256,
SHA384,
Expand Down Expand Up @@ -396,7 +396,7 @@ func (s SigAlg) Genus() GenAlg {
func (s SigAlg) Hash() HshAlg {
switch s {
default:
return UnknownHashAlg
return UnknownHshAlg
case ES224:
return SHA224
case ES256:
Expand Down Expand Up @@ -437,7 +437,7 @@ func (s SigAlg) SigSize() int {
////////////////

////////////////
// HashAlg
// HshAlg
////////////////

func (h *HshAlg) Parse(s string) {
Expand Down
8 changes: 4 additions & 4 deletions alg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func ExampleAlg_Parse() {
"Ed25519ph",
"Ed448",
"UnknownEncAlg",
"UnknownHashAlg",
"UnknownHshAlg",
"SHA-224",
"SHA-256",
"SHA-384",
Expand Down Expand Up @@ -76,7 +76,7 @@ func ExampleAlg_Parse() {
// Ed25519ph
// Ed448
// UnknownEncAlg
// UnknownHashAlg
// UnknownHshAlg
// SHA-224
// SHA-256
// SHA-384
Expand All @@ -99,7 +99,7 @@ func ExampleHshAlg_print() {

func ExampleHshAlg_jsonMarshal() {
type testStruct = struct {
H HshAlg `json:"hashAlg"`
H HshAlg `json:"hshAlg"`
}
z := testStruct{H: SHA256}
jm, err := Marshal(z)
Expand All @@ -109,7 +109,7 @@ func ExampleHshAlg_jsonMarshal() {
fmt.Printf("%+s\n", jm)

// Output:
// {"hashAlg":"SHA-256"}
// {"hshAlg":"SHA-256"}
}

func ExampleCrv_Parse() {
Expand Down
10 changes: 3 additions & 7 deletions canon.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import (
// It returns only top level fields with no recursion or promotion of embedded
// fields.
func Canon(raw json.RawMessage) (can []string, err error) {
ms := MapSlice{}
err = json.Unmarshal(raw, &ms)
o := newOrderedMap()
err = json.Unmarshal(raw, &o)
if err != nil {
return nil, err
}
can = make([]string, len(ms))
for i, v := range ms {
can[i] = v.Key
}
return can, nil
return o.Keys(), nil
}

// Canonical returns the canonical form. Input canon is optional and may be nil.
Expand Down
6 changes: 3 additions & 3 deletions canon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ func ExampleCanonicalHash() {
// Ie3xL77AsiCcb4r0pbnZJqMcfSBqg5Lk0npNJyJ9BC4
}

// Demonstrates expected behavior for invalid HashAlgs.
// Demonstrates expected behavior for invalid HshAlgs.
func ExampleCanonicalHash_invalidAlg() {
_, err := CanonicalHash([]byte(GoldenPay), nil, "")
fmt.Println(err)
_, err = CanonicalHash([]byte(GoldenPay), nil, "test")
fmt.Println(err)
// Output:
// Hash: invalid HashAlg ""
// Hash: invalid HashAlg "test"
// Hash: invalid HshAlg ""
// Hash: invalid HshAlg "test"
}

// Example CanonicalHash for all hashing algos.
Expand Down
17 changes: 7 additions & 10 deletions coze.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ but should not be considered apart of the Coze specification API.
- MarshalPretty
Other auxiliary types and functions, like B64, are reasonable exports for
package Coze, especially compatible implementations are absent from the Go
package Coze, especially since compatible implementations are absent from the Go
standard library.
*/
package coze
Expand Down Expand Up @@ -348,7 +348,7 @@ func Hash(h HshAlg, msg []byte) (digest B64, err error) {
default:
hash := h.goHash()
if hash == nil {
return nil, fmt.Errorf("Hash: invalid HashAlg %q", h)
return nil, fmt.Errorf("Hash: invalid HshAlg %q", h)
}
_, err = hash.Write(msg)
if err != nil {
Expand All @@ -358,7 +358,7 @@ func Hash(h HshAlg, msg []byte) (digest B64, err error) {
}

if len(digest) == 0 { // sanity check
return nil, fmt.Errorf("Hash: digest is empty; given HashAlg %q", h)
return nil, fmt.Errorf("Hash: digest is empty; given HshAlg %q", h)
}
return digest, nil
}
Expand Down Expand Up @@ -396,15 +396,14 @@ func checkDuplicate(d *json.Decoder) error {
case '{':
keys := make(map[string]bool)
for d.More() {
// Get field key.
t, err := d.Token()
t, err := d.Token() // Get field key.
if err != nil {
return err
}

key := t.(string)
if keys[key] { // Check for duplicates.
return ErrJSONDuplicate
return ErrJSONDuplicate(fmt.Errorf("Coze: JSON duplicate field %q", key))
}
keys[key] = true

Expand Down Expand Up @@ -433,7 +432,5 @@ func checkDuplicate(d *json.Decoder) error {
return nil
}

// ErrJSONDuplicate is for applications that need to check for the JSON
// duplicate error. Alternatively, applications need to check for the error
// string, which may change.
var ErrJSONDuplicate = errors.New("Coze: JSON duplicate field name")
// ErrJSONDuplicate allows applications to check for JSON duplicate error.
type ErrJSONDuplicate error
27 changes: 13 additions & 14 deletions coze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,11 @@ func ExamplePay_String_custom() {
func ExamplePay_UnmarshalJSON_duplicate() {
h := &Pay{}
msg := []byte(`{"alg":"ES256","alg":"ES384"}`)

err := json.Unmarshal(msg, h)
fmt.Println(err)

// Output:
// Coze: JSON duplicate field name
// Coze: JSON duplicate field "alg"
}

// Example demonstrating that unmarshalling a `coze` that has duplicate field
Expand All @@ -176,7 +175,7 @@ func ExampleCoze_UnmarshalJSON_duplicate() {
fmt.Println(err)

// Output:
// Coze: JSON duplicate field name
// Coze: JSON duplicate field "pay"
}

// ExampleCoze_embed demonstrates how to embed a JSON `coze` into a third party
Expand Down Expand Up @@ -429,25 +428,25 @@ func ExampleMarshal_jsonRawMessage() {
}

func Test_checkDuplicate(t *testing.T) {
// Duplicate, should error.
data := `{"a": "b", "a":true,"c":["field_3 string 1","field3 string2"], "d": {"e": 1, "e": 2}}`
// Happy path; no duplicate. Should not error.
data := `{"a": "b", "c":"d", "d": {"e": 1, "f": 2}}`
err := checkDuplicate(json.NewDecoder(strings.NewReader(data)))
if err != ErrJSONDuplicate {
t.Fatal("Should have found duplicate.")
if err != nil {
t.Fatal(err)
}

// Recursive check with duplicate in inner struct. Should error.
data = `{"a": "b", "c":"d", "d": {"e": 1, "e": 2}}`
// Duplicate, should error.
data = `{"a": "aValue", "a":true,"c":["field_3 string 1","field3 string2"], "d": {"e": 1, "e": 2}}`
err = checkDuplicate(json.NewDecoder(strings.NewReader(data)))
if err != ErrJSONDuplicate {
if err == nil {
t.Fatal("Should have found duplicate.")
}

// No duplicate. Should not error.
data = `{"a": "b", "c":"d", "d": {"e": 1, "f": 2}}`
// Recursive check with duplicate in inner struct. Should error.
data = `{"a": "aValue", "c":"cValue", "d": {"e": 1, "e": 2}}`
err = checkDuplicate(json.NewDecoder(strings.NewReader(data)))
if err != nil {
t.Fatal(err)
if err == nil {
t.Fatal("Recursive check should have found duplicate.")
}
}

Expand Down
Loading

0 comments on commit 76f019b

Please sign in to comment.