From dbf8547e55728761cc8f620fbc4e940225f09749 Mon Sep 17 00:00:00 2001 From: armfazh Date: Thu, 28 Jul 2022 17:53:41 -0700 Subject: [PATCH] Improves documentation of group interface. --- group/group.go | 122 ++++++++++++++++++++++++++++++++---------- group/group_test.go | 6 +-- group/ristretto255.go | 8 +-- group/short.go | 6 +-- 4 files changed, 103 insertions(+), 39 deletions(-) diff --git a/group/group.go b/group/group.go index 7a06524e6..d95e891f2 100644 --- a/group/group.go +++ b/group/group.go @@ -7,67 +7,131 @@ import ( "io" ) +// Params stores the size in bytes of elements and scalars. type Params struct { ElementLength uint // Length in bytes of an element. CompressedElementLength uint // Length in bytes of a compressed element. ScalarLength uint // Length in bytes of a scalar. } -// Group represents a prime-order group based on elliptic curves. +// Group represents an additive prime-order group based on elliptic curves. type Group interface { Params() *Params // Params returns parameters for the group + // Creates an element of the group set to the identity of the group. NewElement() Element + // Creates a scalar of the group set to zero. NewScalar() Scalar + // Creates an element of the group set to the identity of the group. Identity() Element + // Creates an element of the group set to the generator of the group. Generator() Element + // Returns a scalar set to the group order. Order() Scalar - RandomElement(io.Reader) Element - RandomScalar(io.Reader) Scalar + // RandomElement creates an element chosen at random (using randomness + // from rnd) from the set of group elements. Use crypto/rand.Reader as + // a cryptographically secure random number generator + RandomElement(rnd io.Reader) Element + // RandomScalar creates a scalar chosen at random (using randomness + // from rnd) from the set of group scalars. Use crypto/rand.Reader as + // a cryptographically secure random number generator + RandomScalar(rnd io.Reader) Scalar + // RandomNonZeroScalar creates a scalar chosen at random (using randomness + // from rnd) from the set of group scalars. Use crypto/rand.Reader as + // a cryptographically secure random number generator. It is guaranteed + // the scalar is not zero. RandomNonZeroScalar(io.Reader) Scalar - HashToElement(data, dst []byte) Element - HashToElementNonUniform(b, dst []byte) Element - HashToScalar(data, dst []byte) Scalar + // HashToElement hashes a message (msg) using a domain separation string + // (dst) producing a group element with uniform distribution. + HashToElement(msg, dst []byte) Element + // HashToElementNonUniform hashes a message (msg) using a domain separation + // string (dst) producing a group element with nonuniform distribution. + HashToElementNonUniform(msg, dst []byte) Element + // HashToScalar hashes a message (msg) using a domain separation string + // (dst) producing a group scalar with uniform distribution. + HashToScalar(msg, dst []byte) Scalar } -// Element represents an abstract element of a prime-order group. +// Element represents an element of a prime-order group. type Element interface { + // Returns the group that the element belongs to. Group() Group - Set(Element) Element + // Set the receiver to x, and returns the receiver. + Set(x Element) Element + // Copy returns a new element equal to the receiver. Copy() Element + // IsIdentity returns true if the receiver is the identity element of the + // group. IsIdentity() bool - IsEqual(Element) bool - CMov(int, Element) Element - CSelect(int, Element, Element) Element - Add(Element, Element) Element - Dbl(Element) Element - Neg(Element) Element - Mul(Element, Scalar) Element - MulGen(Scalar) Element + // IsEqual returns true if the receiver is equal to x. + IsEqual(x Element) bool + // CMov sets the receiver to x if b=1; the receiver is unmodified if b=0; + // otherwise panics if b is not 0 or 1. In all the cases, it returns the + // receiver. + CMov(b int, x Element) Element + // CSelect sets the receiver to x if b=1; sets the receiver to y if b=0; + // otherwise panics if b is not 0 or 1. In all the cases, it returns the + // receiver. + CSelect(b int, x, y Element) Element + // Add sets the receiver to x + y, and returns the receiver. + Add(x, y Element) Element + // Dbl sets the receiver to 2 * x, and returns the receiver. + Dbl(x Element) Element + // Neg sets the receiver to -x, and returns the receiver. + Neg(x Element) Element + // Mul sets the receiver to s * x, and returns the receiver. + Mul(x Element, s Scalar) Element + // MulGen sets the receiver to s * Generator(), and returns the receiver. + MulGen(s Scalar) Element + // BinaryMarshaler returns a byte representation of the element. encoding.BinaryMarshaler + // BinaryUnmarshaler recovers an element from a byte representation + // produced either by encoding.BinaryMarshaler or MarshalBinaryCompress. encoding.BinaryUnmarshaler + // MarshalBinaryCompress returns a byte representation of an elment in a + // compact form whenever the group supports it; otherwise, returns the + // same byte representation produced by encoding.BinaryMarshaler. MarshalBinaryCompress() ([]byte, error) } -// Scalar represents an integer scalar. +// Scalar represents a scalar of a prime-order group. type Scalar interface { + // Returns the group that the scalar belongs to. Group() Group - Set(Scalar) Scalar + // Set the receiver to x, and returns the receiver. + Set(x Scalar) Scalar + // Copy returns a new scalar equal to the receiver. Copy() Scalar - IsEqual(Scalar) bool - SetUint64(uint64) - CMov(int, Scalar) Scalar - CSelect(int, Scalar, Scalar) Scalar - Add(Scalar, Scalar) Scalar - Sub(Scalar, Scalar) Scalar - Mul(Scalar, Scalar) Scalar - Neg(Scalar) Scalar - Inv(Scalar) Scalar + // IsEqual returns true if the receiver is equal to x. + IsEqual(x Scalar) bool + // SetUint64 set the receiver to x, and returns the receiver. + SetUint64(x uint64) Scalar + // CMov sets the receiver to x if b=1; the receiver is unmodified if b=0; + // otherwise panics if b is not 0 or 1. In all the cases, it returns the + // receiver. + CMov(b int, x Scalar) Scalar + // CSelect sets the receiver to x if b=1; sets the receiver to y if b=0; + // otherwise panics if b is not 0 or 1. In all the cases, it returns the + // receiver. + CSelect(b int, x, y Scalar) Scalar + // Add sets the receiver to x + y, and returns the receiver. + Add(x, y Scalar) Scalar + // Sub sets the receiver to x - y, and returns the receiver. + Sub(x, y Scalar) Scalar + // Mul sets the receiver to x * y, and returns the receiver. + Mul(x, y Scalar) Scalar + // Neg sets the receiver to -x, and returns the receiver. + Neg(x Scalar) Scalar + // Inv sets the receiver to 1/x, and returns the receiver. + Inv(x Scalar) Scalar + // BinaryMarshaler returns a byte representation of the scalar. encoding.BinaryMarshaler + // BinaryUnmarshaler recovers a scalar from a byte representation produced + // by encoding.BinaryMarshaler. encoding.BinaryUnmarshaler } var ( - ErrType = errors.New("type mismatch") - ErrUnmarshal = errors.New("error unmarshaling") + ErrType = errors.New("group: type mismatch") + ErrUnmarshal = errors.New("group: error unmarshaling") ErrSelector = errors.New("group: selector must be 0 or 1") ) diff --git a/group/group_test.go b/group/group_test.go index 58eca84b2..bf7b53fb9 100644 --- a/group/group_test.go +++ b/group/group_test.go @@ -145,9 +145,9 @@ func testCSelect(t *testing.T, testTimes int, g group.Group) { test.CheckNoErr(t, err, "should fail with dif 0,1") for i := 0; i < testTimes; i++ { - P := g.RandomElement(rand.Reader) - Q := g.RandomElement(rand.Reader) - R := g.RandomElement(rand.Reader) + P = g.RandomElement(rand.Reader) + Q = g.RandomElement(rand.Reader) + R = g.RandomElement(rand.Reader) want := R.Copy() got := P.CSelect(0, Q, R) diff --git a/group/ristretto255.go b/group/ristretto255.go index a9f8c7d85..643d09395 100644 --- a/group/ristretto255.go +++ b/group/ristretto255.go @@ -10,7 +10,7 @@ import ( "github.com/cloudflare/circl/expander" ) -// Ristretto255 is a quotient group generated from edwards25519 curve. +// Ristretto255 is a quotient group generated from the edwards25519 curve. var Ristretto255 Group = ristrettoGroup{} type ristrettoGroup struct{} @@ -202,9 +202,9 @@ func (e *ristrettoElement) UnmarshalBinary(data []byte) error { return e.p.UnmarshalBinary(data) } -func (s *ristrettoScalar) Group() Group { return Ristretto255 } -func (s *ristrettoScalar) String() string { return fmt.Sprintf("0x%x", s.s.Bytes()) } -func (s *ristrettoScalar) SetUint64(n uint64) { s.s.SetUint64(n) } +func (s *ristrettoScalar) Group() Group { return Ristretto255 } +func (s *ristrettoScalar) String() string { return fmt.Sprintf("0x%x", s.s.Bytes()) } +func (s *ristrettoScalar) SetUint64(n uint64) Scalar { s.s.SetUint64(n); return s } func (s *ristrettoScalar) IsEqual(x Scalar) bool { return s.s.Equals(&x.(*ristrettoScalar).s) diff --git a/group/short.go b/group/short.go index 209279617..8373f49ed 100644 --- a/group/short.go +++ b/group/short.go @@ -271,9 +271,9 @@ type wScl struct { k []byte } -func (s *wScl) Group() Group { return s.wG } -func (s *wScl) String() string { return fmt.Sprintf("0x%x", s.k) } -func (s *wScl) SetUint64(n uint64) { s.fromBig(new(big.Int).SetUint64(n)) } +func (s *wScl) Group() Group { return s.wG } +func (s *wScl) String() string { return fmt.Sprintf("0x%x", s.k) } +func (s *wScl) SetUint64(n uint64) Scalar { s.fromBig(new(big.Int).SetUint64(n)); return s } func (s *wScl) IsEqual(a Scalar) bool { aa := s.cvtScl(a) return subtle.ConstantTimeCompare(s.k, aa.k) == 1