├── go.mod ├── go.sum ├── README.md ├── LICENSE ├── scalar.go ├── ristretto255_test.go └── ristretto255.go /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/gtank/ristretto255 2 | 3 | go 1.23 4 | 5 | require filippo.io/edwards25519 v1.1.0 6 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= 2 | filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ristretto255 2 | 3 | [![GoDoc](https://godoc.org/github.com/gtank/ristretto255?status.svg)](https://godoc.org/github.com/gtank/ristretto255) 4 | 5 | Package ristretto255 implements the group operations from 6 | [RFC 9496, Section 4.3](https://datatracker.ietf.org/doc/html/rfc9496#section-4.3) 7 | and the scalar field from 8 | [RFC 9496, Section 4.4](https://datatracker.ietf.org/doc/html/rfc9496#section-4.4). 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 The Go Authors. All rights reserved. 2 | Copyright (c) 2017 George Tankersley. All rights reserved. 3 | Copyright (c) 2019 Henry de Valence. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | * Neither the name of Google Inc. nor the names of its 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /scalar.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package ristretto255 6 | 7 | import ( 8 | "encoding/base64" 9 | "errors" 10 | 11 | "filippo.io/edwards25519" 12 | ) 13 | 14 | // A Scalar is an element of the ristretto255 scalar field, as specified in 15 | // RFC 9496, Section 4.4. That is, an integer modulo 16 | // 17 | // l = 2^252 + 27742317777372353535851937790883648493 18 | // 19 | // The zero value is a valid zero element. 20 | type Scalar struct { 21 | s edwards25519.Scalar 22 | } 23 | 24 | // NewScalar returns a Scalar set to the value 0. 25 | func NewScalar() *Scalar { 26 | return &Scalar{} 27 | } 28 | 29 | // Set sets the value of s to x and returns s. 30 | func (s *Scalar) Set(x *Scalar) *Scalar { 31 | *s = *x 32 | return s 33 | } 34 | 35 | // Add sets s = x + y mod l and returns s. 36 | func (s *Scalar) Add(x, y *Scalar) *Scalar { 37 | s.s.Add(&x.s, &y.s) 38 | return s 39 | } 40 | 41 | // Subtract sets s = x - y mod l and returns s. 42 | func (s *Scalar) Subtract(x, y *Scalar) *Scalar { 43 | s.s.Subtract(&x.s, &y.s) 44 | return s 45 | } 46 | 47 | // Negate sets s = -x mod l and returns s. 48 | func (s *Scalar) Negate(x *Scalar) *Scalar { 49 | s.s.Negate(&x.s) 50 | return s 51 | } 52 | 53 | // Multiply sets s = x * y mod l and returns s. 54 | func (s *Scalar) Multiply(x, y *Scalar) *Scalar { 55 | s.s.Multiply(&x.s, &y.s) 56 | return s 57 | } 58 | 59 | // Invert sets s = 1 / x such that s * x = 1 mod l and returns s. 60 | // 61 | // If x is 0, the result is undefined. 62 | func (s *Scalar) Invert(x *Scalar) *Scalar { 63 | s.s.Invert(&x.s) 64 | return s 65 | } 66 | 67 | // FromUniformBytes sets s to a uniformly distributed value given 64 uniformly 68 | // distributed random bytes. 69 | // 70 | // Deprecated: use SetUniformBytes. This API will be removed before v1.0.0. 71 | func (s *Scalar) FromUniformBytes(x []byte) *Scalar { 72 | if _, err := s.SetUniformBytes(x); err != nil { 73 | panic(err.Error()) 74 | } 75 | return s 76 | } 77 | 78 | // SetUniformBytes sets s to a uniformly distributed value given 64 uniformly 79 | // distributed random bytes by interpreting the 64-byte string as a 512-bit 80 | // unsigned integer in little-endian order and reducing the integer modulo l. 81 | // 82 | // If x is not of the right length, SetUniformBytes returns nil and an error, 83 | // and the receiver is unchanged. 84 | func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) { 85 | if _, err := s.s.SetUniformBytes(x); err != nil { 86 | return nil, errors.New("ristretto255: SetUniformBytes input is not 64 bytes long") 87 | } 88 | return s, nil 89 | } 90 | 91 | // Decode sets s = x, where x is a 32 bytes little-endian encoding of s. If x is 92 | // not a canonical encoding of s, Decode returns an error and the receiver is 93 | // unchanged. 94 | // 95 | // Deprecated: use SetCanonicalBytes. This API will be removed before v1.0.0. 96 | func (s *Scalar) Decode(x []byte) error { 97 | _, err := s.SetCanonicalBytes(x) 98 | return err 99 | } 100 | 101 | // SetCanonicalBytes sets s = x, where x is a 32 bytes little-endian encoding of 102 | // s. If x is not a canonical encoding of s, SetCanonicalBytes returns nil and 103 | // an error and the receiver is unchanged. 104 | func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) { 105 | if _, err := s.s.SetCanonicalBytes(x); err != nil { 106 | return nil, errors.New("ristretto255: " + err.Error()) 107 | } 108 | return s, nil 109 | } 110 | 111 | // Encode appends a 32 bytes little-endian encoding of s to b. 112 | // 113 | // Deprecated: use Bytes. This API will be removed before v1.0.0. 114 | func (s *Scalar) Encode(b []byte) []byte { 115 | ret, out := sliceForAppend(b, 32) 116 | copy(out, s.s.Bytes()) 117 | return ret 118 | } 119 | 120 | // Bytes returns the 32 bytes little-endian canonical encoding of s. 121 | func (s *Scalar) Bytes() []byte { 122 | return s.s.Bytes() 123 | } 124 | 125 | // Equal returns 1 if v and u are equal, and 0 otherwise. 126 | func (s *Scalar) Equal(u *Scalar) int { 127 | return s.s.Equal(&u.s) 128 | } 129 | 130 | // Zero sets s = 0 and returns s. 131 | func (s *Scalar) Zero() *Scalar { 132 | s.s = edwards25519.Scalar{} 133 | return s 134 | } 135 | 136 | // MarshalText implements encoding/TextMarshaler interface 137 | func (s *Scalar) MarshalText() (text []byte, err error) { 138 | b := s.Encode([]byte{}) 139 | return []byte(base64.StdEncoding.EncodeToString(b)), nil 140 | } 141 | 142 | // UnmarshalText implements encoding/TextMarshaler interface 143 | func (s *Scalar) UnmarshalText(text []byte) error { 144 | sb, err := base64.StdEncoding.DecodeString(string(text)) 145 | if err == nil { 146 | return s.Decode(sb) 147 | } 148 | return err 149 | } 150 | 151 | // String implements the Stringer interface 152 | func (s *Scalar) String() string { 153 | result, _ := s.MarshalText() 154 | return string(result) 155 | } 156 | -------------------------------------------------------------------------------- /ristretto255_test.go: -------------------------------------------------------------------------------- 1 | package ristretto255 2 | 3 | import ( 4 | "bytes" 5 | "crypto/sha512" 6 | "encoding/hex" 7 | "encoding/json" 8 | "math/big" 9 | "testing" 10 | 11 | "filippo.io/edwards25519/field" 12 | ) 13 | 14 | // The encoding of the canonical generator. 15 | var compressedRistrettoBasepoint, _ = hex.DecodeString("e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76") 16 | 17 | func TestRistrettoBasepointRoundTrip(t *testing.T) { 18 | decodedBasepoint := &Element{} 19 | err := decodedBasepoint.Decode(compressedRistrettoBasepoint) 20 | if err != nil { 21 | t.Fatal(err) 22 | } 23 | 24 | ristrettoBasepoint := (&Element{}).Base() 25 | if decodedBasepoint.Equal(ristrettoBasepoint) != 1 { 26 | t.Error("decode succeeded, but got wrong point") 27 | } 28 | 29 | roundtripBasepoint := decodedBasepoint.Encode(nil) 30 | if !bytes.Equal(compressedRistrettoBasepoint, roundtripBasepoint) { 31 | t.Error("decode<>encode roundtrip produced different results") 32 | } 33 | 34 | encodedBasepoint := ristrettoBasepoint.Encode(nil) 35 | if !bytes.Equal(compressedRistrettoBasepoint, encodedBasepoint) { 36 | t.Error("point encode produced different results") 37 | } 38 | } 39 | 40 | func TestRistrettoSmallMultiplesTestVectors(t *testing.T) { 41 | // From RFC 9496, Appendix A.1. 42 | var testVectors = [16]string{ 43 | // This is the identity point 44 | "0000000000000000000000000000000000000000000000000000000000000000", 45 | // This is the basepoint 46 | "e2f2ae0a6abc4e71a884a961c500515f58e30b6aa582dd8db6a65945e08d2d76", 47 | // These are small multiples of the basepoint 48 | "6a493210f7499cd17fecb510ae0cea23a110e8d5b901f8acadd3095c73a3b919", 49 | "94741f5d5d52755ece4f23f044ee27d5d1ea1e2bd196b462166b16152a9d0259", 50 | "da80862773358b466ffadfe0b3293ab3d9fd53c5ea6c955358f568322daf6a57", 51 | "e882b131016b52c1d3337080187cf768423efccbb517bb495ab812c4160ff44e", 52 | "f64746d3c92b13050ed8d80236a7f0007c3b3f962f5ba793d19a601ebb1df403", 53 | "44f53520926ec81fbd5a387845beb7df85a96a24ece18738bdcfa6a7822a176d", 54 | "903293d8f2287ebe10e2374dc1a53e0bc887e592699f02d077d5263cdd55601c", 55 | "02622ace8f7303a31cafc63f8fc48fdc16e1c8c8d234b2f0d6685282a9076031", 56 | "20706fd788b2720a1ed2a5dad4952b01f413bcf0e7564de8cdc816689e2db95f", 57 | "bce83f8ba5dd2fa572864c24ba1810f9522bc6004afe95877ac73241cafdab42", 58 | "e4549ee16b9aa03099ca208c67adafcafa4c3f3e4e5303de6026e3ca8ff84460", 59 | "aa52e000df2e16f55fb1032fc33bc42742dad6bd5a8fc0be0167436c5948501f", 60 | "46376b80f409b29dc2b5f6f0c52591990896e5716f41477cd30085ab7f10301e", 61 | "e0c418f7c8d9c4cdd7395b93ea124f3ad99021bb681dfc3302a9d99a2e53e64e", 62 | } 63 | 64 | basepointMultiple := (&Element{}).Zero() 65 | ristrettoBasepoint := (&Element{}).Base() 66 | 67 | for i := range testVectors { 68 | // Grab the bytes of the encoding 69 | encoding, err := hex.DecodeString(testVectors[i]) 70 | if err != nil { 71 | t.Fatalf("#%d: bad hex encoding in test vector: %v", i, err) 72 | } 73 | 74 | // Decode the test vector to a ristretto255 element 75 | decodedPoint := Element{} 76 | err = decodedPoint.Decode(encoding) 77 | if err != nil { 78 | t.Fatalf("#%d: could not decode test vector: %v", i, err) 79 | } 80 | // Re-encode and check round trips 81 | roundtripEncoding := decodedPoint.Encode(nil) 82 | if !bytes.Equal(encoding, roundtripEncoding) { 83 | t.Errorf("#%d: decode<>encode roundtrip failed", i) 84 | } 85 | 86 | // Check that the test vector encodes i * B 87 | if basepointMultiple.Equal(&decodedPoint) != 1 { 88 | t.Errorf("decoded small multiple %d * B is not %d * B", i, i) 89 | } 90 | computedEncoding := basepointMultiple.Encode(nil) 91 | if !bytes.Equal(encoding, computedEncoding) { 92 | t.Errorf("#%d: encoding computed value did not match", i) 93 | } 94 | 95 | // Ensure basepointMultiple = i * B in the next iteration 96 | basepointMultiple.Add(basepointMultiple, ristrettoBasepoint) 97 | } 98 | } 99 | 100 | func TestRistrettoBadEncodingsTestVectors(t *testing.T) { 101 | // From RFC 9496, Appendix A.2. 102 | var testVectors = []string{ 103 | // These are all bad because they're non-canonical field encodings. 104 | "00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 105 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 106 | "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 107 | "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 108 | // These are all bad because they're negative field elements. 109 | "0100000000000000000000000000000000000000000000000000000000000000", 110 | "01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 111 | "ed57ffd8c914fb201471d1c3d245ce3c746fcbe63a3679d51b6a516ebebe0e20", 112 | "c34c4e1826e5d403b78e246e88aa051c36ccf0aafebffe137d148a2bf9104562", 113 | "c940e5a4404157cfb1628b108db051a8d439e1a421394ec4ebccb9ec92a8ac78", 114 | "47cfc5497c53dc8e61c91d17fd626ffb1c49e2bca94eed052281b510b1117a24", 115 | "f1c6165d33367351b0da8f6e4511010c68174a03b6581212c71c0e1d026c3c72", 116 | "87260f7a2f12495118360f02c26a470f450dadf34a413d21042b43b9d93e1309", 117 | // These are all bad because they give a nonsquare x^2. 118 | "26948d35ca62e643e26a83177332e6b6afeb9d08e4268b650f1f5bbd8d81d371", 119 | "4eac077a713c57b4f4397629a4145982c661f48044dd3f96427d40b147d9742f", 120 | "de6a7b00deadc788eb6b6c8d20c0ae96c2f2019078fa604fee5b87d6e989ad7b", 121 | "bcab477be20861e01e4a0e295284146a510150d9817763caf1a6f4b422d67042", 122 | "2a292df7e32cababbd9de088d1d1abec9fc0440f637ed2fba145094dc14bea08", 123 | "f4a9e534fc0d216c44b218fa0c42d99635a0127ee2e53c712f70609649fdff22", 124 | "8268436f8c4126196cf64b3c7ddbda90746a378625f9813dd9b8457077256731", 125 | "2810e5cbc2cc4d4eece54f61c6f69758e289aa7ab440b3cbeaa21995c2f4232b", 126 | // These are all bad because they give a negative xy value. 127 | "3eb858e78f5a7254d8c9731174a94f76755fd3941c0ac93735c07ba14579630e", 128 | "a45fdc55c76448c049a1ab33f17023edfb2be3581e9c7aade8a6125215e04220", 129 | "d483fe813c6ba647ebbfd3ec41adca1c6130c2beeee9d9bf065c8d151c5f396e", 130 | "8a2e1d30050198c65a54483123960ccc38aef6848e1ec8f5f780e8523769ba32", 131 | "32888462f8b486c68ad7dd9610be5192bbeaf3b443951ac1a8118419d9fa097b", 132 | "227142501b9d4355ccba290404bde41575b037693cef1f438c47f8fbf35d1165", 133 | "5c37cc491da847cfeb9281d407efc41e15144c876e0170b499a96a22ed31e01e", 134 | "445425117cb8c90edcbc7c1cc0e74f747f2c1efa5630a967c64f287792a48a4b", 135 | // This is s = -1, which causes y = 0. 136 | "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 137 | } 138 | 139 | basepointMultiple := Element{} 140 | basepointMultiple.Zero() 141 | 142 | for i := range testVectors { 143 | // Grab the bytes of the encoding 144 | encoding, err := hex.DecodeString(testVectors[i]) 145 | if err != nil { 146 | t.Fatalf("#%d: bad hex encoding in test vector: %v", i, err) 147 | } 148 | 149 | // Attempt decoding 150 | decodedPoint := Element{} 151 | err = decodedPoint.Decode(encoding) 152 | if err == nil { 153 | t.Fatalf("#%d: did not fail on bad encoding", i) 154 | } 155 | } 156 | } 157 | 158 | func TestRistrettoFromUniformBytesTestVectors(t *testing.T) { 159 | // From RFC 9496, Appendix A.3, except the RFC published the SHA-512 images. 160 | inputs := []string{ 161 | "Ristretto is traditionally a short shot of espresso coffee", 162 | "made with the normal amount of ground coffee but extracted with", 163 | "about half the amount of water in the same amount of time", 164 | "by using a finer grind.", 165 | "This produces a concentrated shot of coffee per volume.", 166 | "Just pulling a normal shot short will produce a weaker shot", 167 | "and is not a Ristretto as some believe.", 168 | } 169 | elements := []string{ 170 | "3066f82a1a747d45120d1740f14358531a8f04bbffe6a819f86dfe50f44a0a46", 171 | "f26e5b6f7d362d2d2a94c5d0e7602cb4773c95a2e5c31a64f133189fa76ed61b", 172 | "006ccd2a9e6867e6a2c5cea83d3302cc9de128dd2a9a57dd8ee7b9d7ffe02826", 173 | "f8f0c87cf237953c5890aec3998169005dae3eca1fbb04548c635953c817f92a", 174 | "ae81e7dedf20a497e10c304a765c1767a42d6e06029758d2d7e8ef7cc4c41179", 175 | "e2705652ff9f5e44d3e841bf1c251cf7dddb77d140870d1ab2ed64f1a9ce8628", 176 | "80bd07262511cdde4863f8a7434cef696750681cb9510eea557088f76d9e5065", 177 | } 178 | 179 | var element Element 180 | for i, input := range inputs { 181 | hash := sha512.Sum512([]byte(input)) 182 | element.FromUniformBytes(hash[:]) 183 | if encoding := hex.EncodeToString(element.Encode(nil)); encoding != elements[i] { 184 | t.Errorf("#%d: expected %q, got %q", i, elements[i], encoding) 185 | } 186 | } 187 | } 188 | 189 | func TestEquivalentFromUniformBytes(t *testing.T) { 190 | // From RFC 9496, Appendix A.3. 191 | inputs := []string{ 192 | "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + 193 | "1200000000000000000000000000000000000000000000000000000000000000", 194 | "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f" + 195 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 196 | "0000000000000000000000000000000000000000000000000000000000000080" + 197 | "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", 198 | "0000000000000000000000000000000000000000000000000000000000000000" + 199 | "1200000000000000000000000000000000000000000000000000000000000080", 200 | } 201 | expected := "304282791023b73128d277bdcb5c7746ef2eac08dde9f2983379cb8e5ef0517f" 202 | 203 | var element Element 204 | for i, input := range inputs { 205 | h, err := hex.DecodeString(input) 206 | if err != nil { 207 | t.Fatalf("#%d: bad hex encoding in test vector: %v", i, err) 208 | } 209 | 210 | element.FromUniformBytes(h[:]) 211 | if encoding := hex.EncodeToString(element.Encode(nil)); encoding != expected { 212 | t.Errorf("#%d: expected %q, got %q", i, expected, encoding) 213 | } 214 | } 215 | } 216 | 217 | func TestMarshalScalar(t *testing.T) { 218 | x := new(Scalar) 219 | // generate an arbitrary scalar 220 | xbytes := sha512.Sum512([]byte("Hello World")) 221 | x.SetUniformBytes(xbytes[:]) 222 | text, err := json.Marshal(x) 223 | if err != nil { 224 | t.Fatalf("Could not marshal json: %v", err) 225 | } 226 | t.Logf("json: %s", text) 227 | y := new(Scalar) 228 | err = json.Unmarshal(text, y) 229 | if err != nil || y.Equal(x) == 0 { 230 | t.Fatalf("Error unmarshaling scalar from json: %s %v", text, err) 231 | } 232 | } 233 | 234 | func TestMarshalElement(t *testing.T) { 235 | x := new(Element) 236 | // generate an arbitrary element 237 | xbytes := sha512.Sum512([]byte("Hello World")) 238 | x.FromUniformBytes(xbytes[:]) 239 | text, err := json.Marshal(x) 240 | if err != nil { 241 | t.Fatalf("Could not marshal json: %v", err) 242 | } 243 | t.Logf("json: %s", text) 244 | y := new(Element) 245 | err = json.Unmarshal(text, y) 246 | if err != nil || y.Equal(x) == 0 { 247 | t.Fatalf("Error unmarshaling element from json: %s %v", text, err) 248 | } 249 | } 250 | 251 | func TestElementSet(t *testing.T) { 252 | // Test this, because the internal point type being hard-copyable isn't part of the spec. 253 | 254 | el1 := NewIdentityElement() 255 | el2 := NewGeneratorElement() 256 | 257 | if el1.Equal(el2) == 1 { 258 | t.Error("shouldn't be the same") 259 | } 260 | 261 | // Check new value 262 | el1.Set(el2) 263 | 264 | if el1.Equal(el2) == 0 { 265 | t.Error("failed to set the value") 266 | } 267 | 268 | // Mutate source var 269 | el2.Add(el2, el2) 270 | 271 | if el1.Equal(el2) == 1 { 272 | t.Error("shouldn't have changed") 273 | } 274 | } 275 | 276 | func TestScalarSet(t *testing.T) { 277 | // Test this, because the internal scalar representation being hard-copyable isn't part of the spec. 278 | 279 | // 32-byte little endian value of "1" 280 | scOne := make([]byte, 32) 281 | scOne[0] = 0x01 282 | 283 | sc1, sc2 := NewScalar(), NewScalar() 284 | 285 | // sc1 <- 1 286 | sc1.SetCanonicalBytes(scOne) 287 | 288 | // 1 != 0 289 | if sc1.Equal(sc2) == 1 { 290 | t.Error("shouldn't be the same") 291 | } 292 | 293 | // sc2 <- sc1 294 | sc2.Set(sc1) 295 | 296 | // 1 == 1 297 | if sc1.Equal(sc2) == 0 { 298 | t.Error("failed to set the value") 299 | } 300 | 301 | // sc1 <- 1 + 1 302 | sc1.Add(sc1, sc1) 303 | 304 | // 2 != 1 305 | if sc1.Equal(sc2) == 1 { 306 | t.Error("shouldn't have changed") 307 | } 308 | } 309 | 310 | func TestConstants(t *testing.T) { 311 | // From RFC 9496, Section 4.1. 312 | t.Run("d", func(t *testing.T) { 313 | testConstant(t, d, 314 | "37095705934669439343138083508754565189542113879843219016388785533085940283555") 315 | }) 316 | t.Run("sqrtM1", func(t *testing.T) { 317 | testConstant(t, sqrtM1, 318 | "19681161376707505956807079304988542015446066515923890162744021073123829784752") 319 | }) 320 | t.Run("sqrtADMinusOne", func(t *testing.T) { 321 | testConstant(t, sqrtADMinusOne, 322 | "25063068953384623474111414158702152701244531502492656460079210482610430750235") 323 | }) 324 | t.Run("invSqrtAMinusD", func(t *testing.T) { 325 | testConstant(t, invSqrtAMinusD, 326 | "54469307008909316920995813868745141605393597292927456921205312896311721017578") 327 | }) 328 | t.Run("oneMinusDSQ", func(t *testing.T) { 329 | testConstant(t, oneMinusDSQ, 330 | "1159843021668779879193775521855586647937357759715417654439879720876111806838") 331 | }) 332 | t.Run("dMinusOneSQ", func(t *testing.T) { 333 | testConstant(t, dMinusOneSQ, 334 | "40440834346308536858101042469323190826248399146238708352240133220865137265952") 335 | }) 336 | } 337 | 338 | func testConstant(t *testing.T, f *field.Element, decimal string) { 339 | b, ok := new(big.Int).SetString(decimal, 10) 340 | if !ok { 341 | t.Fatal("invalid decimal") 342 | } 343 | buf := b.FillBytes(make([]byte, 32)) 344 | for i := 0; i < len(buf)/2; i++ { 345 | buf[i], buf[len(buf)-i-1] = buf[len(buf)-i-1], buf[i] 346 | } 347 | if !bytes.Equal(f.Bytes(), buf) { 348 | t.Errorf("expected %x", buf) 349 | } 350 | } 351 | -------------------------------------------------------------------------------- /ristretto255.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 The Go Authors. All rights reserved. 2 | // Copyright 2019 George Tankersley. All rights reserved. 3 | // Use of this source code is governed by a BSD-style 4 | // license that can be found in the LICENSE file. 5 | 6 | // Package ristretto255 implements the group of prime order 7 | // 8 | // 2**252 + 27742317777372353535851937790883648493 9 | // 10 | // and its scalar field, as specified in RFC 9496, Section 4. 11 | // 12 | // All operations are constant time unless otherwise specified. 13 | package ristretto255 14 | 15 | import ( 16 | "bytes" 17 | "encoding/base64" 18 | "errors" 19 | 20 | "filippo.io/edwards25519" 21 | "filippo.io/edwards25519/field" 22 | ) 23 | 24 | // Constants from RFC 9496, Section 4.1. 25 | // See TestConstants for their decimal values. 26 | var ( 27 | d, _ = new(field.Element).SetBytes([]byte{ 28 | 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 29 | 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00, 30 | 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 31 | 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52, 32 | }) 33 | sqrtM1, _ = new(field.Element).SetBytes([]byte{ 34 | 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4, 35 | 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f, 36 | 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b, 37 | 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b, 38 | }) 39 | sqrtADMinusOne, _ = new(field.Element).SetBytes([]byte{ 40 | 0x1b, 0x2e, 0x7b, 0x49, 0xa0, 0xf6, 0x97, 0x7e, 41 | 0xbd, 0x54, 0x78, 0x1b, 0x0c, 0x8e, 0x9d, 0xaf, 42 | 0xfd, 0xd1, 0xf5, 0x31, 0xc9, 0xfc, 0x3c, 0x0f, 43 | 0xac, 0x48, 0x83, 0x2b, 0xbf, 0x31, 0x69, 0x37, 44 | }) 45 | invSqrtAMinusD, _ = new(field.Element).SetBytes([]byte{ 46 | 0xea, 0x40, 0x5d, 0x80, 0xaa, 0xfd, 0xc8, 0x99, 47 | 0xbe, 0x72, 0x41, 0x5a, 0x17, 0x16, 0x2f, 0x9d, 48 | 0x40, 0xd8, 0x01, 0xfe, 0x91, 0x7b, 0xc2, 0x16, 49 | 0xa2, 0xfc, 0xaf, 0xcf, 0x05, 0x89, 0x6c, 0x78, 50 | }) 51 | oneMinusDSQ, _ = new(field.Element).SetBytes([]byte{ 52 | 0x76, 0xc1, 0x5f, 0x94, 0xc1, 0x09, 0x7c, 0xe2, 53 | 0x0f, 0x35, 0x5e, 0xcd, 0x38, 0xa1, 0x81, 0x2c, 54 | 0xe4, 0xdf, 0x70, 0xbe, 0xdd, 0xab, 0x94, 0x99, 55 | 0xd7, 0xe0, 0xb3, 0xb2, 0xa8, 0x72, 0x90, 0x02, 56 | }) 57 | dMinusOneSQ, _ = new(field.Element).SetBytes([]byte{ 58 | 0x20, 0x4d, 0xed, 0x44, 0xaa, 0x5a, 0xad, 0x31, 59 | 0x99, 0x19, 0x1e, 0xb0, 0x2c, 0x4a, 0x9e, 0xd2, 60 | 0xeb, 0x4e, 0x9b, 0x52, 0x2f, 0xd3, 0xdc, 0x4c, 61 | 0x41, 0x22, 0x6c, 0xf6, 0x7a, 0xb3, 0x68, 0x59, 62 | }) 63 | ) 64 | 65 | var ( 66 | zero = new(field.Element) 67 | one = new(field.Element).One() 68 | two = new(field.Element).Add(one, one) 69 | minusOne = new(field.Element).Subtract(zero, one) 70 | ) 71 | 72 | // Element is an element of the ristretto255 prime-order group. 73 | type Element struct { 74 | r edwards25519.Point 75 | } 76 | 77 | // NewElement returns a new Element set to the identity value. 78 | // 79 | // Deprecated: use NewIdentityElement. This API will be removed before v1.0.0. 80 | func NewElement() *Element { 81 | return NewIdentityElement() 82 | } 83 | 84 | // NewIdentityElement returns a new Element set to the identity value. 85 | func NewIdentityElement() *Element { 86 | e := &Element{} 87 | e.r.Set(edwards25519.NewIdentityPoint()) 88 | return e 89 | } 90 | 91 | // NewGeneratorElement returns a new Element set to the canonical generator. 92 | func NewGeneratorElement() *Element { 93 | e := &Element{} 94 | e.r.Set(edwards25519.NewGeneratorPoint()) 95 | return e 96 | } 97 | 98 | // Set sets the value of e to x and returns e. 99 | func (e *Element) Set(x *Element) *Element { 100 | *e = *x 101 | return e 102 | } 103 | 104 | // Equal returns 1 if e is equivalent to ee, and 0 otherwise. 105 | // 106 | // Equal implements the Equals operation from RFC 9496, Section 4.3.3. 107 | func (e *Element) Equal(ee *Element) int { 108 | X1, Y1, _, _ := e.r.ExtendedCoordinates() 109 | X2, Y2, _, _ := ee.r.ExtendedCoordinates() 110 | 111 | var f0, f1 field.Element 112 | 113 | f0.Multiply(X1, Y2) // x1 * y2 114 | f1.Multiply(Y1, X2) // y1 * x2 115 | out := f0.Equal(&f1) 116 | 117 | f0.Multiply(Y1, Y2) // y1 * y2 118 | f1.Multiply(X1, X2) // x1 * x2 119 | out = out | f0.Equal(&f1) 120 | 121 | return out 122 | } 123 | 124 | // FromUniformBytes maps the 64-byte slice b to e uniformly and 125 | // deterministically, and returns e. This can be used for hash-to-group 126 | // operations or to obtain a random element. 127 | // 128 | // Deprecated: use SetUniformBytes. This API will be removed before v1.0.0. 129 | func (e *Element) FromUniformBytes(b []byte) *Element { 130 | if _, err := e.SetUniformBytes(b); err != nil { 131 | panic(err.Error()) 132 | } 133 | return e 134 | } 135 | 136 | // SetUniformBytes deterministically sets e to a uniformly distributed value 137 | // given 64 uniformly distributed random bytes. 138 | // 139 | // This can be used for hash-to-group operations or to obtain a random element. 140 | // 141 | // SetUniformBytes implements the Element Derivation operation from RFC 9496, 142 | // Section 4.3.4. 143 | func (e *Element) SetUniformBytes(b []byte) (*Element, error) { 144 | if len(b) != 64 { 145 | return nil, errors.New("ristretto255: SetUniformBytes input is not 64 bytes long") 146 | } 147 | 148 | f := &field.Element{} 149 | 150 | f.SetBytes(b[:32]) 151 | point1 := &Element{} 152 | mapToPoint(&point1.r, f) 153 | 154 | f.SetBytes(b[32:]) 155 | point2 := &Element{} 156 | mapToPoint(&point2.r, f) 157 | 158 | return e.Add(point1, point2), nil 159 | } 160 | 161 | // mapToPoint implements MAP from Section 3.2.4 of draft-hdevalence-cfrg-ristretto-00. 162 | func mapToPoint(out *edwards25519.Point, t *field.Element) { 163 | // r = SQRT_M1 * t^2 164 | r := &field.Element{} 165 | r.Multiply(sqrtM1, r.Square(t)) 166 | 167 | // u = (r + 1) * ONE_MINUS_D_SQ 168 | u := &field.Element{} 169 | u.Multiply(u.Add(r, one), oneMinusDSQ) 170 | 171 | // c = -1 172 | c := &field.Element{} 173 | c.Set(minusOne) 174 | 175 | // v = (c - r*D) * (r + D) 176 | rPlusD := &field.Element{} 177 | rPlusD.Add(r, d) 178 | v := &field.Element{} 179 | v.Multiply(v.Subtract(c, v.Multiply(r, d)), rPlusD) 180 | 181 | // (was_square, s) = SQRT_RATIO_M1(u, v) 182 | s := &field.Element{} 183 | _, wasSquare := s.SqrtRatio(u, v) 184 | 185 | // s_prime = -CT_ABS(s*t) 186 | sPrime := &field.Element{} 187 | sPrime.Negate(sPrime.Absolute(sPrime.Multiply(s, t))) 188 | 189 | // s = CT_SELECT(s IF was_square ELSE s_prime) 190 | s.Select(s, sPrime, wasSquare) 191 | // c = CT_SELECT(c IF was_square ELSE r) 192 | c.Select(c, r, wasSquare) 193 | 194 | // N = c * (r - 1) * D_MINUS_ONE_SQ - v 195 | N := &field.Element{} 196 | N.Multiply(c, N.Subtract(r, one)) 197 | N.Subtract(N.Multiply(N, dMinusOneSQ), v) 198 | 199 | s2 := &field.Element{} 200 | s2.Square(s) 201 | 202 | // w0 = 2 * s * v 203 | w0 := &field.Element{} 204 | w0.Add(w0, w0.Multiply(s, v)) 205 | // w1 = N * SQRT_AD_MINUS_ONE 206 | w1 := &field.Element{} 207 | w1.Multiply(N, sqrtADMinusOne) 208 | // w2 = 1 - s^2 209 | w2 := &field.Element{} 210 | w2.Subtract(one, s2) 211 | // w3 = 1 + s^2 212 | w3 := &field.Element{} 213 | w3.Add(one, s2) 214 | 215 | // return (w0*w3, w2*w1, w1*w3, w0*w2) 216 | var X, Y, Z, T field.Element 217 | X.Multiply(w0, w3) 218 | Y.Multiply(w2, w1) 219 | Z.Multiply(w1, w3) 220 | T.Multiply(w0, w2) 221 | if _, err := out.SetExtendedCoordinates(&X, &Y, &Z, &T); err != nil { 222 | panic("ristretto255: internal error: MAP generated invalid coordinates") 223 | } 224 | } 225 | 226 | // Encode appends the 32 bytes canonical encoding of e to b 227 | // and returns the result. 228 | // 229 | // Deprecated: use Bytes. This API will be removed before v1.0.0. 230 | func (e *Element) Encode(b []byte) []byte { 231 | ret, out := sliceForAppend(b, 32) 232 | e.bytes(out) 233 | return ret 234 | } 235 | 236 | // sliceForAppend takes a slice and a requested number of bytes. It returns a 237 | // slice with the contents of the given slice followed by that many bytes and a 238 | // second slice that aliases into it and contains only the extra bytes. If the 239 | // original slice has sufficient capacity then no allocation is performed. 240 | func sliceForAppend(in []byte, n int) (head, tail []byte) { 241 | if total := len(in) + n; cap(in) >= total { 242 | head = in[:total] 243 | } else { 244 | head = make([]byte, total) 245 | copy(head, in) 246 | } 247 | tail = head[len(in):] 248 | return 249 | } 250 | 251 | // Bytes returns the 32 bytes canonical encoding of e. 252 | // 253 | // Bytes implements the Encode operation from RFC 9496, Section 4.3.2. 254 | func (e *Element) Bytes() []byte { 255 | // Bytes is outlined to let the allocation happen on the stack of the caller. 256 | b := make([]byte, 32) 257 | return e.bytes(b) 258 | } 259 | 260 | func (e *Element) bytes(b []byte) []byte { 261 | X, Y, Z, T := e.r.ExtendedCoordinates() 262 | tmp := &field.Element{} 263 | 264 | // u1 = (z0 + y0) * (z0 - y0) 265 | u1 := &field.Element{} 266 | u1.Add(Z, Y).Multiply(u1, tmp.Subtract(Z, Y)) 267 | 268 | // u2 = x0 * y0 269 | u2 := &field.Element{} 270 | u2.Multiply(X, Y) 271 | 272 | // Ignore was_square since this is always square 273 | // (_, invsqrt) = SQRT_RATIO_M1(1, u1 * u2^2) 274 | invSqrt := &field.Element{} 275 | invSqrt.SqrtRatio(one, tmp.Square(u2).Multiply(tmp, u1)) 276 | 277 | // den1 = invsqrt * u1 278 | // den2 = invsqrt * u2 279 | den1, den2 := &field.Element{}, &field.Element{} 280 | den1.Multiply(invSqrt, u1) 281 | den2.Multiply(invSqrt, u2) 282 | // z_inv = den1 * den2 * t0 283 | zInv := &field.Element{} 284 | zInv.Multiply(den1, den2).Multiply(zInv, T) 285 | 286 | // ix0 = x0 * SQRT_M1 287 | // iy0 = y0 * SQRT_M1 288 | ix0, iy0 := &field.Element{}, &field.Element{} 289 | ix0.Multiply(X, sqrtM1) 290 | iy0.Multiply(Y, sqrtM1) 291 | // enchanted_denominator = den1 * INVSQRT_A_MINUS_D 292 | enchantedDenominator := &field.Element{} 293 | enchantedDenominator.Multiply(den1, invSqrtAMinusD) 294 | 295 | // rotate = IS_NEGATIVE(t0 * z_inv) 296 | rotate := tmp.Multiply(T, zInv).IsNegative() 297 | 298 | // x = CT_SELECT(iy0 IF rotate ELSE x0) 299 | // y = CT_SELECT(ix0 IF rotate ELSE y0) 300 | x, y := &field.Element{}, &field.Element{} 301 | x.Select(iy0, X, rotate) 302 | y.Select(ix0, Y, rotate) 303 | // z = z0 304 | z := Z 305 | // den_inv = CT_SELECT(enchanted_denominator IF rotate ELSE den2) 306 | denInv := &field.Element{} 307 | denInv.Select(enchantedDenominator, den2, rotate) 308 | 309 | // y = CT_NEG(y, IS_NEGATIVE(x * z_inv)) 310 | isNegative := tmp.Multiply(x, zInv).IsNegative() 311 | y.Select(tmp.Negate(y), y, isNegative) 312 | 313 | // s = CT_ABS(den_inv * (z - y)) 314 | s := tmp.Subtract(z, y).Multiply(tmp, denInv).Absolute(tmp) 315 | 316 | // Return the canonical little-endian encoding of s. 317 | copy(b, s.Bytes()) 318 | return b 319 | } 320 | 321 | var errInvalidEncoding = errors.New("ristretto255: invalid element encoding") 322 | 323 | // Decode sets e to the decoded value of in. If in is not a 32 byte canonical 324 | // encoding, Decode returns an error, and the receiver is unchanged. 325 | // 326 | // Deprecated: use SetCanonicalBytes. This API will be removed before v1.0.0. 327 | func (e *Element) Decode(in []byte) error { 328 | _, err := e.SetCanonicalBytes(in) 329 | return err 330 | } 331 | 332 | // SetCanonicalBytes sets e to the decoded value of in. If in is not a canonical 333 | // encoding of s, SetCanonicalBytes returns nil and an error and the receiver is 334 | // unchanged. 335 | // 336 | // SetCanonicalBytes implements the Decode operation from RFC 9496, Section 4.3.1. 337 | func (e *Element) SetCanonicalBytes(in []byte) (*Element, error) { 338 | if len(in) != 32 { 339 | return nil, errInvalidEncoding 340 | } 341 | 342 | // First, interpret the string as an integer s in little-endian representation. 343 | s := &field.Element{} 344 | s.SetBytes(in) 345 | 346 | // If the resulting value is >= p, decoding fails. 347 | if !bytes.Equal(s.Bytes(), in) { 348 | return nil, errInvalidEncoding 349 | } 350 | 351 | // If IS_NEGATIVE(s) returns TRUE, decoding fails. 352 | if s.IsNegative() == 1 { 353 | return nil, errInvalidEncoding 354 | } 355 | 356 | // ss = s^2 357 | sSqr := &field.Element{} 358 | sSqr.Square(s) 359 | 360 | // u1 = 1 - ss 361 | u1 := &field.Element{} 362 | u1.Subtract(one, sSqr) 363 | 364 | // u2 = 1 + ss 365 | u2 := &field.Element{} 366 | u2.Add(one, sSqr) 367 | 368 | // u2_sqr = u2^2 369 | u2Sqr := &field.Element{} 370 | u2Sqr.Square(u2) 371 | 372 | // v = -(D * u1^2) - u2_sqr 373 | v := &field.Element{} 374 | v.Square(u1).Multiply(v, d).Negate(v).Subtract(v, u2Sqr) 375 | 376 | // (was_square, invsqrt) = SQRT_RATIO_M1(1, v * u2_sqr) 377 | invSqrt, tmp := &field.Element{}, &field.Element{} 378 | _, wasSquare := invSqrt.SqrtRatio(one, tmp.Multiply(v, u2Sqr)) 379 | 380 | // den_x = invsqrt * u2 381 | // den_y = invsqrt * den_x * v 382 | denX, denY := &field.Element{}, &field.Element{} 383 | denX.Multiply(invSqrt, u2) 384 | denY.Multiply(invSqrt, denX).Multiply(denY, v) 385 | 386 | // x = CT_ABS(2 * s * den_x) 387 | // y = u1 * den_y 388 | // t = x * y 389 | var X, Y, Z, T field.Element 390 | X.Multiply(two, s).Multiply(&X, denX).Absolute(&X) 391 | Y.Multiply(u1, denY) 392 | Z.One() 393 | T.Multiply(&X, &Y) 394 | 395 | // If was_square is FALSE, or IS_NEGATIVE(t) returns TRUE, or y = 0, decoding fails. 396 | if wasSquare == 0 || T.IsNegative() == 1 || Y.Equal(zero) == 1 { 397 | return nil, errInvalidEncoding 398 | } 399 | 400 | // Otherwise, return the internal representation in extended coordinates (x, y, 1, t). 401 | if _, err := e.r.SetExtendedCoordinates(&X, &Y, &Z, &T); err != nil { 402 | panic("ristretto255: internal error: DECODE generated invalid coordinates") 403 | } 404 | return e, nil 405 | } 406 | 407 | // ScalarBaseMult sets e = s * B, where B is the canonical generator, and returns e. 408 | func (e *Element) ScalarBaseMult(s *Scalar) *Element { 409 | e.r.ScalarBaseMult(&s.s) 410 | return e 411 | } 412 | 413 | // ScalarMult sets e = s * p, and returns e. 414 | func (e *Element) ScalarMult(s *Scalar, p *Element) *Element { 415 | e.r.ScalarMult(&s.s, &p.r) 416 | return e 417 | } 418 | 419 | // MultiScalarMult sets e = sum(s[i] * p[i]), and returns e. 420 | // 421 | // Execution time depends only on the lengths of the two slices, which must match. 422 | func (e *Element) MultiScalarMult(s []*Scalar, p []*Element) *Element { 423 | if len(p) != len(s) { 424 | panic("ristretto255: MultiScalarMult invoked with mismatched slice lengths") 425 | } 426 | points := make([]*edwards25519.Point, len(p)) 427 | scalars := make([]*edwards25519.Scalar, len(s)) 428 | for i := range s { 429 | points[i] = &p[i].r 430 | scalars[i] = &s[i].s 431 | } 432 | e.r.MultiScalarMult(scalars, points) 433 | return e 434 | } 435 | 436 | // VarTimeMultiScalarMult sets e = sum(s[i] * p[i]), and returns e. 437 | // 438 | // Execution time depends on the inputs. 439 | func (e *Element) VarTimeMultiScalarMult(s []*Scalar, p []*Element) *Element { 440 | if len(p) != len(s) { 441 | panic("ristretto255: VarTimeMultiScalarMult invoked with mismatched slice lengths") 442 | } 443 | points := make([]*edwards25519.Point, len(p)) 444 | scalars := make([]*edwards25519.Scalar, len(s)) 445 | for i := range s { 446 | points[i] = &p[i].r 447 | scalars[i] = &s[i].s 448 | } 449 | e.r.VarTimeMultiScalarMult(scalars, points) 450 | return e 451 | } 452 | 453 | // VarTimeDoubleScalarBaseMult sets e = a * A + b * B, where B is the canonical 454 | // generator, and returns e. 455 | // 456 | // Execution time depends on the inputs. 457 | func (e *Element) VarTimeDoubleScalarBaseMult(a *Scalar, A *Element, b *Scalar) *Element { 458 | e.r.VarTimeDoubleScalarBaseMult(&a.s, &A.r, &b.s) 459 | return e 460 | } 461 | 462 | // Add sets e = p + q, and returns e. 463 | func (e *Element) Add(p, q *Element) *Element { 464 | e.r.Add(&p.r, &q.r) 465 | return e 466 | } 467 | 468 | // Subtract sets e = p - q, and returns e. 469 | func (e *Element) Subtract(p, q *Element) *Element { 470 | e.r.Subtract(&p.r, &q.r) 471 | return e 472 | } 473 | 474 | // Negate sets e = -p, and returns e. 475 | func (e *Element) Negate(p *Element) *Element { 476 | e.r.Negate(&p.r) 477 | return e 478 | } 479 | 480 | // Zero sets e to the identity element of the group, and returns e. 481 | // 482 | // Deprecated: use NewIdentityElement and Set. This API will be removed before v1.0.0. 483 | func (e *Element) Zero() *Element { 484 | return e.Set(NewIdentityElement()) 485 | } 486 | 487 | // Base sets e to the canonical generator, and returns e. 488 | // 489 | // Deprecated: use NewGeneratorElement and Set. This API will be removed before v1.0.0. 490 | func (e *Element) Base() *Element { 491 | return e.Set(NewGeneratorElement()) 492 | } 493 | 494 | // MarshalText implements encoding/TextMarshaler interface 495 | func (e *Element) MarshalText() (text []byte, err error) { 496 | b := e.Encode([]byte{}) 497 | return []byte(base64.StdEncoding.EncodeToString(b)), nil 498 | } 499 | 500 | // UnmarshalText implements encoding/TextMarshaler interface 501 | func (e *Element) UnmarshalText(text []byte) error { 502 | eb, err := base64.StdEncoding.DecodeString(string(text)) 503 | if err == nil { 504 | return e.Decode(eb) 505 | } 506 | return err 507 | } 508 | 509 | // String implements the Stringer interface 510 | func (e *Element) String() string { 511 | result, _ := e.MarshalText() 512 | return string(result) 513 | } 514 | --------------------------------------------------------------------------------