Fix chainlink key generation/validation
This commit is contained in:
parent
7993a72dea
commit
8f333ba0fd
|
@ -21,6 +21,7 @@ import (
|
|||
// q is the field characteristic (cardinality) of the secp256k1 base field. All
|
||||
// arithmetic operations on the field are modulo this.
|
||||
var q = s256.P
|
||||
var halfQ = new(big.Int).Div(q, big.NewInt(2))
|
||||
|
||||
type fieldElt big.Int
|
||||
|
||||
|
@ -28,17 +29,17 @@ type fieldElt big.Int
|
|||
func newFieldZero() *fieldElt { return (*fieldElt)(big.NewInt(0)) }
|
||||
|
||||
// Int returns f as a big.Int
|
||||
func (f *fieldElt) int() *big.Int { return (*big.Int)(f) }
|
||||
func (f *fieldElt) Int() *big.Int { return (*big.Int)(f) }
|
||||
|
||||
// modQ reduces f's underlying big.Int modulo q, and returns it
|
||||
func (f *fieldElt) modQ() *fieldElt {
|
||||
if f.int().Cmp(q) != -1 || f.int().Cmp(bigZero) == -1 {
|
||||
if f.Int().Cmp(q) != -1 || f.Int().Cmp(bigZero) == -1 {
|
||||
// f ∉ {0, ..., q-1}. Find the representative of f+qℤ in that set.
|
||||
//
|
||||
// Per Mod docstring, "Mod implements Euclidean modulus", meaning that after
|
||||
// this, f will be the smallest non-negative representative of its
|
||||
// equivalence class in ℤ/qℤ. TODO(alx): Make this faster
|
||||
f.int().Mod(f.int(), q)
|
||||
f.Int().Mod(f.Int(), q)
|
||||
}
|
||||
return f
|
||||
}
|
||||
|
@ -55,7 +56,7 @@ var bigZero = big.NewInt(0)
|
|||
|
||||
// String returns the string representation of f
|
||||
func (f *fieldElt) String() string {
|
||||
return fmt.Sprintf("fieldElt{%x}", f.int())
|
||||
return fmt.Sprintf("fieldElt{%x}", f.Int())
|
||||
}
|
||||
|
||||
// Equal returns true iff f=g, i.e. the backing big.Ints satisfy f ≡ g mod q
|
||||
|
@ -69,30 +70,30 @@ func (f *fieldElt) Equal(g *fieldElt) bool {
|
|||
if g == (*fieldElt)(nil) { // g is nil, f is not
|
||||
return false
|
||||
}
|
||||
return bigZero.Cmp(newFieldZero().Sub(f, g).modQ().int()) == 0
|
||||
return bigZero.Cmp(newFieldZero().Sub(f, g).modQ().Int()) == 0
|
||||
}
|
||||
|
||||
// Add sets f to the sum of a and b modulo q, and returns it.
|
||||
func (f *fieldElt) Add(a, b *fieldElt) *fieldElt {
|
||||
f.int().Add(a.int(), b.int())
|
||||
f.Int().Add(a.Int(), b.Int())
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
// Sub sets f to a-b mod q, and returns it.
|
||||
func (f *fieldElt) Sub(a, b *fieldElt) *fieldElt {
|
||||
f.int().Sub(a.int(), b.int())
|
||||
f.Int().Sub(a.Int(), b.Int())
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
// Set sets f's value to v, and returns f.
|
||||
func (f *fieldElt) Set(v *fieldElt) *fieldElt {
|
||||
f.int().Set(v.int())
|
||||
f.Int().Set(v.Int())
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
// SetInt sets f's value to v mod q, and returns f.
|
||||
func (f *fieldElt) SetInt(v *big.Int) *fieldElt {
|
||||
f.int().Set(v)
|
||||
f.Int().Set(v)
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
|
@ -103,7 +104,7 @@ func (f *fieldElt) Pick(rand cipher.Stream) *fieldElt {
|
|||
|
||||
// Neg sets f to the negation of g modulo q, and returns it
|
||||
func (f *fieldElt) Neg(g *fieldElt) *fieldElt {
|
||||
f.int().Neg(g.int())
|
||||
f.Int().Neg(g.Int())
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
|
@ -113,13 +114,13 @@ func (f *fieldElt) Clone() *fieldElt { return newFieldZero().Set(f.modQ()) }
|
|||
// SetBytes sets f to the 32-byte big-endian value represented by buf, reduces
|
||||
// it, and returns it.
|
||||
func (f *fieldElt) SetBytes(buf [32]byte) *fieldElt {
|
||||
f.int().SetBytes(buf[:])
|
||||
f.Int().SetBytes(buf[:])
|
||||
return f.modQ()
|
||||
}
|
||||
|
||||
// Bytes returns the 32-byte big-endian representation of f
|
||||
func (f *fieldElt) Bytes() [32]byte {
|
||||
bytes := f.modQ().int().Bytes()
|
||||
bytes := f.modQ().Int().Bytes()
|
||||
if len(bytes) > 32 {
|
||||
panic("field element longer than 256 bits")
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ var two = big.NewInt(2)
|
|||
|
||||
// square returns y² mod q
|
||||
func fieldSquare(y *fieldElt) *fieldElt {
|
||||
return fieldEltFromBigInt(newFieldZero().int().Exp(y.int(), two, q))
|
||||
return fieldEltFromBigInt(newFieldZero().Int().Exp(y.Int(), two, q))
|
||||
}
|
||||
|
||||
// sqrtPower is s.t. n^sqrtPower≡sqrt(n) mod q, if n has a root at all. See
|
||||
|
@ -146,7 +147,7 @@ var sqrtPower = s256.QPlus1Div4()
|
|||
// maybeSqrtInField returns a square root of v, if it has any, else nil
|
||||
func maybeSqrtInField(v *fieldElt) *fieldElt {
|
||||
s := newFieldZero()
|
||||
s.int().Exp(v.int(), sqrtPower, q)
|
||||
s.Int().Exp(v.Int(), sqrtPower, q)
|
||||
if !fieldSquare(s).Equal(v) {
|
||||
return nil
|
||||
}
|
||||
|
@ -159,11 +160,11 @@ var seven = fieldEltFromInt(7)
|
|||
// rightHandSide returns the RHS of the secp256k1 equation, x³+7 mod q, given x
|
||||
func rightHandSide(x *fieldElt) *fieldElt {
|
||||
xCubed := newFieldZero()
|
||||
xCubed.int().Exp(x.int(), three, q)
|
||||
xCubed.Int().Exp(x.Int(), three, q)
|
||||
return xCubed.Add(xCubed, seven)
|
||||
}
|
||||
|
||||
// isEven returns true if f is even, false otherwise
|
||||
func (f *fieldElt) isEven() bool {
|
||||
return big.NewInt(0).Mod(f.int(), two).Cmp(big.NewInt(0)) == 0
|
||||
return big.NewInt(0).Mod(f.Int(), two).Cmp(big.NewInt(0)) == 0
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func TestField_SmokeTestPick(t *testing.T) {
|
|||
f := newFieldZero()
|
||||
f.Pick(randomStream)
|
||||
observedFieldElt(t, f)
|
||||
assert.True(t, f.int().Cmp(big.NewInt(1000000000)) == 1,
|
||||
assert.True(t, f.Int().Cmp(big.NewInt(1000000000)) == 1,
|
||||
"should be greater than 1000000000, with very high probability")
|
||||
}
|
||||
|
||||
|
@ -132,9 +132,9 @@ func TestField_MaybeSquareRootInField(t *testing.T) {
|
|||
for i := 0; i < numFieldSamples; i++ {
|
||||
f.Pick(randomStream)
|
||||
observedFieldElt(t, f)
|
||||
require.True(t, f.int().Cmp(q) == -1, "picked larger value than q: %s", f)
|
||||
require.True(t, f.int().Cmp(big.NewInt(-1)) != -1,
|
||||
"backing int must be non-negative")
|
||||
require.True(t, f.Int().Cmp(q) == -1, "picked larger value than q: %s", f)
|
||||
require.True(t, f.Int().Cmp(big.NewInt(-1)) != -1,
|
||||
"backing Int must be non-negative")
|
||||
s := fieldSquare(f)
|
||||
g := maybeSqrtInField(s)
|
||||
require.NotEqual(t, g, (*fieldElt)(nil))
|
||||
|
@ -142,11 +142,11 @@ func TestField_MaybeSquareRootInField(t *testing.T) {
|
|||
require.True(t, f.Equal(g) || f.Equal(ng), "squaring something and "+
|
||||
"taking the square root should give ± the original: failed with %s", f)
|
||||
bigIntSqrt := newFieldZero() // Cross-check against big.ModSqrt
|
||||
rv := bigIntSqrt.int().ModSqrt(s.int(), q)
|
||||
rv := bigIntSqrt.Int().ModSqrt(s.Int(), q)
|
||||
require.NotNil(t, rv)
|
||||
require.True(t, bigIntSqrt.Equal(g) || bigIntSqrt.Equal(ng))
|
||||
nonSquare := newFieldZero().Neg(s)
|
||||
rv = bigIntSqrt.int().ModSqrt(nonSquare.int(), q)
|
||||
rv = bigIntSqrt.Int().ModSqrt(nonSquare.Int(), q)
|
||||
require.Nil(t, rv, "ModSqrt indicates nonSquare is square")
|
||||
require.Nil(t, maybeSqrtInField(nonSquare), "the negative of square "+
|
||||
"should not be a square")
|
||||
|
|
|
@ -148,8 +148,8 @@ func (P *Secp256k1Point) Data() ([]byte, error) {
|
|||
// Add sets P to a+b (secp256k1 group operation) and returns it.
|
||||
func (P *Secp256k1Point) Add(a, b kyber.Point) kyber.Point {
|
||||
X, Y := s256.Add(
|
||||
a.(*Secp256k1Point).X.int(), a.(*Secp256k1Point).Y.int(),
|
||||
b.(*Secp256k1Point).X.int(), b.(*Secp256k1Point).Y.int())
|
||||
a.(*Secp256k1Point).X.Int(), a.(*Secp256k1Point).Y.Int(),
|
||||
b.(*Secp256k1Point).X.Int(), b.(*Secp256k1Point).Y.Int())
|
||||
P.X.SetInt(X)
|
||||
P.Y.SetInt(Y)
|
||||
return P
|
||||
|
@ -158,9 +158,9 @@ func (P *Secp256k1Point) Add(a, b kyber.Point) kyber.Point {
|
|||
// Add sets P to a-b (secp256k1 group operation), and returns it.
|
||||
func (P *Secp256k1Point) Sub(a, b kyber.Point) kyber.Point {
|
||||
X, Y := s256.Add(
|
||||
a.(*Secp256k1Point).X.int(), a.(*Secp256k1Point).Y.int(),
|
||||
b.(*Secp256k1Point).X.int(),
|
||||
newFieldZero().Neg(b.(*Secp256k1Point).Y).int()) // -b_y
|
||||
a.(*Secp256k1Point).X.Int(), a.(*Secp256k1Point).Y.Int(),
|
||||
b.(*Secp256k1Point).X.Int(),
|
||||
newFieldZero().Neg(b.(*Secp256k1Point).Y).Int()) // -b_y
|
||||
P.X.SetInt(X)
|
||||
P.Y.SetInt(Y)
|
||||
return P
|
||||
|
@ -185,8 +185,8 @@ func (P *Secp256k1Point) Mul(s kyber.Scalar, a kyber.Point) kyber.Point {
|
|||
if a == (*Secp256k1Point)(nil) || a == nil {
|
||||
X, Y = s256.ScalarBaseMult(sBytes)
|
||||
} else {
|
||||
X, Y = s256.ScalarMult(a.(*Secp256k1Point).X.int(),
|
||||
a.(*Secp256k1Point).Y.int(), sBytes)
|
||||
X, Y = s256.ScalarMult(a.(*Secp256k1Point).X.Int(),
|
||||
a.(*Secp256k1Point).Y.Int(), sBytes)
|
||||
}
|
||||
P.X.SetInt(X)
|
||||
P.Y.SetInt(Y)
|
||||
|
@ -309,7 +309,7 @@ func IsSecp256k1Point(p kyber.Point) bool {
|
|||
|
||||
// Coordinates returns the coordinates of p
|
||||
func Coordinates(p kyber.Point) (*big.Int, *big.Int) {
|
||||
return p.(*Secp256k1Point).X.int(), p.(*Secp256k1Point).Y.int()
|
||||
return p.(*Secp256k1Point).X.Int(), p.(*Secp256k1Point).Y.Int()
|
||||
}
|
||||
|
||||
// ValidPublicKey returns true iff p can be used in the optimized on-chain
|
||||
|
@ -322,6 +322,13 @@ func ValidPublicKey(p kyber.Point) bool {
|
|||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify that X < HALF_Q so it can be used for optimized on-chain verification
|
||||
if P.X.Int().Cmp(halfQ) == 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify that the pub key is a valid curve point
|
||||
maybeY := maybeSqrtInField(rightHandSide(P.X))
|
||||
return maybeY != nil && (P.Y.Equal(maybeY) || P.Y.Equal(maybeY.Neg(maybeY)))
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func TestPoint_Embed(t *testing.T) {
|
|||
_, err := rand.Read(data)
|
||||
require.Nil(t, err)
|
||||
p.Embed(data, randomStreamPoint)
|
||||
require.True(t, s256.IsOnCurve(p.X.int(), p.Y.int()),
|
||||
require.True(t, s256.IsOnCurve(p.X.Int(), p.Y.Int()),
|
||||
"should embed to a secp256k1 point")
|
||||
output, err := p.Data()
|
||||
require.NoError(t, err)
|
||||
|
|
Loading…
Reference in New Issue