-
Notifications
You must be signed in to change notification settings - Fork 0
/
helpers.go
95 lines (77 loc) · 2.34 KB
/
helpers.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright (c) 2024 Yawning Angel
//
// SPDX-License-Identifier: BSD-3-Clause
package bs255
import (
"crypto/rand"
"errors"
"fmt"
"io"
"github.com/gtank/ristretto255"
"gitlab.com/yawning/tuplehash"
)
const (
wideScalarSize = 64
maxRetries = 3
)
var (
scZero = ristretto255.NewScalar()
geIdentity = ristretto255.NewIdentityElement()
errTooManyRetries = errors.New("bs255: too many rejection sampling retries")
)
func sampleNonZeroScalar(xof *tuplehash.Hasher) (*ristretto255.Scalar, error) {
sc := ristretto255.NewScalar()
var tmp [wideScalarSize]byte
for i := 0; i < maxRetries; i++ {
_, _ = xof.Read(tmp[:])
_, _ = sc.SetUniformBytes(tmp[:]) // Can't fail.
// This is the one and only edge case, which occurs when
// sampling the signature nonce `k`.
//
// The probability of this occurring is cryptographically
// insignificant, so implementations MAY choose to fail
// instead (and in fact BIP-0340 specifies an abort when
// signing if this happens).
//
// This implementation opts for rejection-sampling as XOFs
// are pretty great, but in practical terms it is astronomically
// unlikely that a decision here makes an actual difference,
// and more importantly, has no impact on what is considered
// a valid signature.
//
// In either case, this check MUST be done in constant time.
if sc.Equal(scZero) == 0 {
return sc, nil
}
}
return nil, errTooManyRetries
}
func geIsIdentity(ge *ristretto255.Element) bool {
return ge.Equal(geIdentity) == 1
}
func writeAuxRand(xof *tuplehash.Hasher, rng io.Reader) error {
const auxRandSize = 32
if rng == nil {
rng = rand.Reader
}
// If the rng is explicitly `DeterministicSign`, write the
// empty string as a tuple element.
//
// Supporting this is entirely optional, and implementors
// MAY choose to do something entirely different, and this
// too, does not impact what is considered a valid signature.
if _, ok := rng.(*deterministicSignatureReader); ok {
_, _ = xof.Write([]byte{})
return nil
}
var tmp [auxRandSize]byte
if _, err := rng.Read(tmp[:]); err != nil {
return fmt.Errorf("%w: %w", errRngFailure, err)
}
_, _ = xof.Write(tmp[:])
return nil
}
type deterministicSignatureReader struct{}
func (r *deterministicSignatureReader) Read(_ []byte) (int, error) {
panic("bs255: DeterministicSign is not intended to be called")
}