From 90177b295f2b702ebd009466abe133aa83b5bd0d Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 22 Mar 2023 14:22:46 -0500 Subject: [PATCH] fix: invalid infinity point encoding --- ecc/bls12-377/marshal.go | 43 ++++++++++++++++--- ecc/bls12-378/marshal.go | 43 ++++++++++++++++--- ecc/bls12-381/marshal.go | 43 ++++++++++++++++--- ecc/bls24-315/marshal.go | 41 ++++++++++++++++-- ecc/bls24-317/marshal.go | 41 ++++++++++++++++-- ecc/bn254/marshal.go | 37 +++++++++++++--- ecc/bw6-633/marshal.go | 41 ++++++++++++++++-- ecc/bw6-756/marshal.go | 41 ++++++++++++++++-- ecc/bw6-761/marshal.go | 41 ++++++++++++++++-- .../generator/ecc/template/marshal.go.tmpl | 29 +++++++++++-- 10 files changed, 357 insertions(+), 43 deletions(-) diff --git a/ecc/bls12-377/marshal.go b/ecc/bls12-377/marshal.go index b71e1c2dc..6140b863d 100644 --- a/ecc/bls12-377/marshal.go +++ b/ecc/bls12-377/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bls12-377 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -861,7 +885,7 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - // p.X.A1 | p.X.A0 + // p.X.A1 | p.X.A0 fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) @@ -927,13 +951,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1063,9 +1093,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bls12-378/marshal.go b/ecc/bls12-378/marshal.go index 2b12b7bbb..33bd800dd 100644 --- a/ecc/bls12-378/marshal.go +++ b/ecc/bls12-378/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bls12-378 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -861,7 +885,7 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - // p.X.A1 | p.X.A0 + // p.X.A1 | p.X.A0 fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) @@ -927,13 +951,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1063,9 +1093,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bls12-381/marshal.go b/ecc/bls12-381/marshal.go index fad5940db..f1efa51ff 100644 --- a/ecc/bls12-381/marshal.go +++ b/ecc/bls12-381/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bls12-381 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -861,7 +885,7 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - // p.X.A1 | p.X.A0 + // p.X.A1 | p.X.A0 fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[48:48+fp.Bytes]), p.X.A0) fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) @@ -927,13 +951,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1063,9 +1093,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bls24-315/marshal.go b/ecc/bls24-315/marshal.go index 79fbab810..10e20cefe 100644 --- a/ecc/bls24-315/marshal.go +++ b/ecc/bls24-315/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bls24-315 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -933,13 +957,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1087,9 +1117,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bls24-317/marshal.go b/ecc/bls24-317/marshal.go index 8f50f8e17..d353ba8e3 100644 --- a/ecc/bls24-317/marshal.go +++ b/ecc/bls24-317/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bls24-317 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -933,13 +957,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1087,9 +1117,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bn254/marshal.go b/ecc/bn254/marshal.go index f980f6f16..fe66b9a92 100644 --- a/ecc/bn254/marshal.go +++ b/ecc/bn254/marshal.go @@ -44,6 +44,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bn254 object values to an output stream type Encoder struct { w io.Writer @@ -359,6 +361,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -670,8 +685,11 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil @@ -787,9 +805,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -854,7 +875,7 @@ func (p *G2Affine) Bytes() (res [SizeOfG2AffineCompressed]byte) { } // we store X and mask the most significant word with our metadata mask - // p.X.A1 | p.X.A0 + // p.X.A1 | p.X.A0 fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[32:32+fp.Bytes]), p.X.A0) fp.BigEndian.PutElement((*[fp.Bytes]byte)(res[0:0+fp.Bytes]), p.X.A1) @@ -920,8 +941,11 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil @@ -1051,9 +1075,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bw6-633/marshal.go b/ecc/bw6-633/marshal.go index 78c1df948..4325dbc38 100644 --- a/ecc/bw6-633/marshal.go +++ b/ecc/bw6-633/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bw6-633 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -921,13 +945,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1043,9 +1073,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bw6-756/marshal.go b/ecc/bw6-756/marshal.go index 8a3a01315..868b34577 100644 --- a/ecc/bw6-756/marshal.go +++ b/ecc/bw6-756/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bw6-756 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -921,13 +945,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1043,9 +1073,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/ecc/bw6-761/marshal.go b/ecc/bw6-761/marshal.go index ad6160197..54bf3ed50 100644 --- a/ecc/bw6-761/marshal.go +++ b/ecc/bw6-761/marshal.go @@ -50,6 +50,8 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") + // Encoder writes bw6-761 object values to an output stream type Encoder struct { w io.Writer @@ -365,6 +367,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + func (enc *Encoder) encode(v interface{}) (err error) { rv := reflect.ValueOf(v) if v == nil || (rv.Kind() == reflect.Ptr && rv.IsNil()) { @@ -674,13 +689,19 @@ func (p *G1Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG1AffineUncompressed, nil @@ -796,9 +817,12 @@ func (p *G1Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG1AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } @@ -921,13 +945,19 @@ func (p *G2Affine) setBytes(buf []byte, subGroupCheck bool) (int, error) { } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if mData == mCompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineCompressed, nil } if mData == mUncompressedInfinity { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineUncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOfG2AffineUncompressed, nil @@ -1043,9 +1073,12 @@ func (p *G2Affine) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, err er mData := buf[0] & mMask if mData == mCompressedInfinity { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOfG2AffineCompressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil } diff --git a/internal/generator/ecc/template/marshal.go.tmpl b/internal/generator/ecc/template/marshal.go.tmpl index 4f31c9c3e..fb1a9aa61 100644 --- a/internal/generator/ecc/template/marshal.go.tmpl +++ b/internal/generator/ecc/template/marshal.go.tmpl @@ -54,6 +54,7 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT +var ErrInvalidInfinityEncoding = errors.New("invalid infinity point encoding") // Encoder writes {{.Name}} object values to an output stream type Encoder struct { @@ -377,6 +378,19 @@ func NoSubgroupChecks() func(*Decoder) { } } +// isZeroed checks that the provided bytes are at 0 +func isZeroed(firstByte byte, buf []byte) bool { + if firstByte != 0 { + return false + } + for _, b := range buf { + if b != 0 { + return false + } + } + return true +} + {{template "encode" dict "Raw" ""}} {{template "encode" dict "Raw" "Raw"}} @@ -564,7 +578,7 @@ func (p *{{ $.TAffine }}) Bytes() (res [SizeOf{{ $.TAffine }}Compressed]byte) { // we store X and mask the most significant word with our metadata mask {{- if eq $.CoordType "fptower.E2"}} - // p.X.A1 | p.X.A0 + // p.X.A1 | p.X.A0 {{- $offset := $.sizeOfFp}} {{- template "putFp" dict "all" .all "OffSet" $offset "From" "p.X.A0"}} {{- template "putFp" dict "all" .all "OffSet" 0 "From" "p.X.A1"}} @@ -681,8 +695,11 @@ func (p *{{ $.TAffine }}) setBytes(buf []byte, subGroupCheck bool) (int, error) } } - // if infinity is encoded in the metadata, we don't need to read the buffer + // infinity encoded, we still check that the buffer is full of zeroes. if (mData == mCompressedInfinity) { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOf{{ $.TAffine }}Compressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOf{{ $.TAffine }}Compressed, nil @@ -690,6 +707,9 @@ func (p *{{ $.TAffine }}) setBytes(buf []byte, subGroupCheck bool) (int, error) {{- if ge .all.FpUnusedBits 3}} if (mData == mUncompressedInfinity) { + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOf{{ $.TAffine }}Uncompressed]) { + return 0, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() return SizeOf{{ $.TAffine }}Uncompressed, nil @@ -901,9 +921,12 @@ func (p *{{ $.TAffine }}) unsafeSetCompressedBytes(buf []byte) (isInfinity bool, mData := buf[0] & mMask if (mData == mCompressedInfinity) { + isInfinity = true + if !isZeroed(buf[0] & ^mMask, buf[1:SizeOf{{ $.TAffine }}Compressed]) { + return isInfinity, ErrInvalidInfinityEncoding + } p.X.SetZero() p.Y.SetZero() - isInfinity = true return isInfinity, nil }