Skip to content

Commit

Permalink
优化 bign 曲线
Browse files Browse the repository at this point in the history
  • Loading branch information
deatil committed Sep 30, 2024
1 parent 952025a commit 0c6d2c1
Show file tree
Hide file tree
Showing 19 changed files with 12,656 additions and 32 deletions.
9 changes: 6 additions & 3 deletions elliptic/bign/bign.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package bign

import (
"sync"
"encoding/asn1"
"crypto/elliptic"
)
Expand All @@ -11,17 +12,19 @@ var (
OIDNamedCurveP512v1 = asn1.ObjectIdentifier{1, 2, 112, 0, 2, 0, 34, 101, 45, 3, 3}
)

var initonce sync.Once

func P256v1() elliptic.Curve {
once.Do(initAll)
initonce.Do(initAll)
return p256v1
}

func P384v1() elliptic.Curve {
once.Do(initAll)
initonce.Do(initAll)
return p384v1
}

func P512v1() elliptic.Curve {
once.Do(initAll)
initonce.Do(initAll)
return p512v1
}
69 changes: 40 additions & 29 deletions elliptic/bign/bign_curves.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
package bign

import (
"sync"
"math/big"
"crypto/elliptic"
)

var (
once sync.Once
p256v1, p384v1, p512v1 *elliptic.CurveParams
bign_curve "github.com/deatil/go-cryptobin/elliptic/bign/curve"
)

func initAll() {
Expand All @@ -17,37 +13,52 @@ func initAll() {
initP512v1()
}

var p256v1 = &bignCurve[*bign_curve.P256Point]{
newPoint: bign_curve.NewP256Point,
}

func initP256v1() {
p256v1 = new(elliptic.CurveParams)
p256v1.P = bigFromHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43")
p256v1.N = bigFromHex("ffffffffffffffffffffffffffffffffd95c8ed60dfb4dfc7e5abf99263d6607")
p256v1.B = bigFromHex("77ce6c1515f3a8edd2c13aabe4d8fbbe4cf55069978b9253b22e7d6bd69c03f1")
p256v1.Gx = bigFromHex("0000000000000000000000000000000000000000000000000000000000000000")
p256v1.Gy = bigFromHex("6bf7fc3cfb16d69f5ce4c9a351d6835d78913966c408f6521e29cf1804516a93")
p256v1.BitSize = 256
p256v1.Name = "BIGN256V1"
p256v1.params = &elliptic.CurveParams{
Name: "BIGN256V1",
BitSize: 256,
P: bigFromHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff43"),
N: bigFromHex("ffffffffffffffffffffffffffffffffd95c8ed60dfb4dfc7e5abf99263d6607"),
B: bigFromHex("77ce6c1515f3a8edd2c13aabe4d8fbbe4cf55069978b9253b22e7d6bd69c03f1"),
Gx: bigFromHex("0000000000000000000000000000000000000000000000000000000000000000"),
Gy: bigFromHex("6bf7fc3cfb16d69f5ce4c9a351d6835d78913966c408f6521e29cf1804516a93"),
}
}

var p384v1 = &bignCurve[*bign_curve.P384Point]{
newPoint: bign_curve.NewP384Point,
}

func initP384v1() {
p384v1 = new(elliptic.CurveParams)
p384v1.P = bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3")
p384v1.N = bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffe6cccc40373af7bbb8046dae7a6a4ff0a3db7dc3ff30ca7b7")
p384v1.B = bigFromHex("3c75dfe1959cef2033075aab655d34d2712748bb0ffbb196a6216af9e9712e3a14bde2f0f3cebd7cbca7fc236873bf64")
p384v1.Gx = bigFromHex("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
p384v1.Gy = bigFromHex("5d438224a82e9e9e6330117e432dbf893a729a11dc86ffa00549e79e66b1d35584403e276b2a42f9ea5ecb31f733c451")
p384v1.BitSize = 384
p384v1.Name = "BIGN384V1"
p384v1.params = &elliptic.CurveParams{
Name: "BIGN384V1",
BitSize: 384,
P: bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec3"),
N: bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffe6cccc40373af7bbb8046dae7a6a4ff0a3db7dc3ff30ca7b7"),
B: bigFromHex("3c75dfe1959cef2033075aab655d34d2712748bb0ffbb196a6216af9e9712e3a14bde2f0f3cebd7cbca7fc236873bf64"),
Gx: bigFromHex("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
Gy: bigFromHex("5d438224a82e9e9e6330117e432dbf893a729a11dc86ffa00549e79e66b1d35584403e276b2a42f9ea5ecb31f733c451"),
}
}

var p512v1 = &bignCurve[*bign_curve.P512Point]{
newPoint: bign_curve.NewP512Point,
}

func initP512v1() {
p512v1 = new(elliptic.CurveParams)
p512v1.P = bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7")
p512v1.N = bigFromHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2c0092c0198004ef26bebb02e2113f4361bcae59556df32dcffad490d068ef1")
p512v1.B = bigFromHex("6cb45944933b8c43d88c5d6a60fd58895bc6a9eedd5d255117ce13e3daadb0882711dcb5c4245e952933008c87aca243ea8622273a49a27a09346998d6139c90")
p512v1.Gx = bigFromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
p512v1.Gy = bigFromHex("a826ff7ae4037681b182e6f7a0d18fabb0ab41b3b361bce2d2edf81b00cccada6973dde20efa6fd2ff777395eee8226167aa83b9c94c0d04b792ae6fceefedbd")
p512v1.BitSize = 512
p512v1.Name = "BIGN512V1"
p512v1.params = &elliptic.CurveParams{
Name: "BIGN512V1",
BitSize: 512,
P: bigFromHex("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdc7"),
N: bigFromHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2c0092c0198004ef26bebb02e2113f4361bcae59556df32dcffad490d068ef1"),
B: bigFromHex("6cb45944933b8c43d88c5d6a60fd58895bc6a9eedd5d255117ce13e3daadb0882711dcb5c4245e952933008c87aca243ea8622273a49a27a09346998d6139c90"),
Gx: bigFromHex("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
Gy: bigFromHex("a826ff7ae4037681b182e6f7a0d18fabb0ab41b3b361bce2d2edf81b00cccada6973dde20efa6fd2ff777395eee8226167aa83b9c94c0d04b792ae6fceefedbd"),
}
}

func bigFromHex(s string) *big.Int {
Expand Down
178 changes: 178 additions & 0 deletions elliptic/bign/curve.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package bign

import (
"errors"
"math/big"
"crypto/elliptic"
)

// bignPoint is a generic constraint for the bign Point types.
type bignPoint[T any] interface {
Bytes() []byte
SetBytes([]byte) (T, error)
Add(T, T) T
Double(T) T
ScalarMult(T, []byte) (T, error)
ScalarBaseMult([]byte) (T, error)
}

// bignCurve is a Curve implementation based on a bign Point.
type bignCurve[Point bignPoint[Point]] struct {
newPoint func() Point
params *elliptic.CurveParams
}

func (curve *bignCurve[Point]) Params() *elliptic.CurveParams {
return curve.params
}

func (curve *bignCurve[Point]) IsOnCurve(x, y *big.Int) bool {
// IsOnCurve is documented to reject (0, 0), the conventional point at
// infinity, which however is accepted by pointFromAffine.
if x.Sign() == 0 && y.Sign() == 0 {
return false
}
_, err := curve.pointFromAffine(x, y)
return err == nil
}

func (curve *bignCurve[Point]) pointFromAffine(x, y *big.Int) (p Point, err error) {
// (0, 0) is by convention the point at infinity, which can't be represented
// in affine coordinates. See Issue 37294.
if x.Sign() == 0 && y.Sign() == 0 {
return curve.newPoint(), nil
}
// Reject values that would not get correctly encoded.
if x.Sign() < 0 || y.Sign() < 0 {
return p, errors.New("negative coordinate")
}
if x.BitLen() > curve.params.BitSize || y.BitLen() > curve.params.BitSize {
return p, errors.New("overflowing coordinate")
}
// Encode the coordinates and let SetBytes reject invalid points.
byteLen := (curve.params.BitSize + 7) / 8
buf := make([]byte, 1+2*byteLen)
buf[0] = 4 // uncompressed point
x.FillBytes(buf[1 : 1+byteLen])
y.FillBytes(buf[1+byteLen : 1+2*byteLen])
return curve.newPoint().SetBytes(buf)
}

func (curve *bignCurve[Point]) pointToAffine(p Point) (x, y *big.Int) {
out := p.Bytes()
if len(out) == 1 && out[0] == 0 {
// This is the encoding of the point at infinity, which the affine
// coordinates API represents as (0, 0) by convention.
return new(big.Int), new(big.Int)
}
byteLen := (curve.params.BitSize + 7) / 8
x = new(big.Int).SetBytes(out[1 : 1+byteLen])
y = new(big.Int).SetBytes(out[1+byteLen:])
return x, y
}

func (curve *bignCurve[Point]) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
p1, err := curve.pointFromAffine(x1, y1)
if err != nil {
panic("crypto/elliptic: Add was called on an invalid point")
}
p2, err := curve.pointFromAffine(x2, y2)
if err != nil {
panic("crypto/elliptic: Add was called on an invalid point")
}
return curve.pointToAffine(p1.Add(p1, p2))
}

func (curve *bignCurve[Point]) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
p, err := curve.pointFromAffine(x1, y1)
if err != nil {
panic("crypto/elliptic: Double was called on an invalid point")
}
return curve.pointToAffine(p.Double(p))
}

// normalizeScalar brings the scalar within the byte size of the order of the
// curve, as expected by the bign scalar multiplication functions.
func (curve *bignCurve[Point]) normalizeScalar(scalar []byte) []byte {
byteSize := (curve.params.N.BitLen() + 7) / 8
if len(scalar) == byteSize {
return scalar
}
s := new(big.Int).SetBytes(scalar)
if len(scalar) > byteSize {
s.Mod(s, curve.params.N)
}
out := make([]byte, byteSize)
return s.FillBytes(out)
}

func (curve *bignCurve[Point]) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
p, err := curve.pointFromAffine(Bx, By)
if err != nil {
panic("crypto/elliptic: ScalarMult was called on an invalid point")
}
scalar = curve.normalizeScalar(scalar)
p, err = p.ScalarMult(p, scalar)
if err != nil {
panic("crypto/elliptic: bign rejected normalized scalar")
}
return curve.pointToAffine(p)
}

func (curve *bignCurve[Point]) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
scalar = curve.normalizeScalar(scalar)
p, err := curve.newPoint().ScalarBaseMult(scalar)
if err != nil {
panic("crypto/elliptic: bign rejected normalized scalar")
}
return curve.pointToAffine(p)
}

// CombinedMult returns [s1]G + [s2]P where G is the generator. It's used
// through an interface upgrade in crypto/ecdsa.
func (curve *bignCurve[Point]) CombinedMult(Px, Py *big.Int, s1, s2 []byte) (x, y *big.Int) {
s1 = curve.normalizeScalar(s1)
q, err := curve.newPoint().ScalarBaseMult(s1)
if err != nil {
panic("crypto/elliptic: bign rejected normalized scalar")
}
p, err := curve.pointFromAffine(Px, Py)
if err != nil {
panic("crypto/elliptic: CombinedMult was called on an invalid point")
}
s2 = curve.normalizeScalar(s2)
p, err = p.ScalarMult(p, s2)
if err != nil {
panic("crypto/elliptic: bign rejected normalized scalar")
}
return curve.pointToAffine(p.Add(p, q))
}

func (curve *bignCurve[Point]) Unmarshal(data []byte) (x, y *big.Int) {
if len(data) == 0 || data[0] != 4 {
return nil, nil
}
// Use SetBytes to check that data encodes a valid point.
_, err := curve.newPoint().SetBytes(data)
if err != nil {
return nil, nil
}
// We don't use pointToAffine because it involves an expensive field
// inversion to convert from Jacobian to affine coordinates, which we
// already have.
byteLen := (curve.params.BitSize + 7) / 8
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
y = new(big.Int).SetBytes(data[1+byteLen:])
return x, y
}

func (curve *bignCurve[Point]) UnmarshalCompressed(data []byte) (x, y *big.Int) {
if len(data) == 0 || (data[0] != 2 && data[0] != 3) {
return nil, nil
}
p, err := curve.newPoint().SetBytes(data)
if err != nil {
return nil, nil
}
return curve.pointToAffine(p)
}
11 changes: 11 additions & 0 deletions elliptic/bign/curve/fiat/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2021 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.

FROM coqorg/coq:8.20.0

RUN git clone https://github.com/mit-plv/fiat-crypto && cd fiat-crypto && \
git submodule update --init --recursive
RUN cd fiat-crypto && eval $(opam env) && make standalone-ocaml SKIP_BEDROCK2=1

ENV PATH /home/coq/fiat-crypto/src/ExtractionOCaml:$PATH
34 changes: 34 additions & 0 deletions elliptic/bign/curve/fiat/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
The code in this package was autogenerated by the fiat-crypto project
at version v0.0.9 from a formally verified model, and by the addchain
project at a recent tip version.

docker build -t fiat-crypto:v0.0.9 .
go install github.com/mmcloughlin/addchain/cmd/addchain@v0.4.0
go run generate.go

fiat-crypto code comes under the following license.

Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The authors are listed at

https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS
Loading

0 comments on commit 0c6d2c1

Please sign in to comment.