You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
548 lines
18 KiB
548 lines
18 KiB
//go:build ignore
|
|
|
|
// Prints test/vectors/bls12381_vectors.json: the Go reference values for the
|
|
// BLS12-381 code of lib/src/bls12381_*.dart, from the libraries that drand
|
|
// and tlock use for Quicknet: github.com/kilic/bls12-381 and
|
|
// github.com/drand/kyber-bls12381 over it.
|
|
//
|
|
// - points: the frozen edge-case encodings of datekeys-ts
|
|
// (src/lib/dkc/testing/bls12381-vectors.json; valid points, sign-bit
|
|
// flips, identity encodings with stray flags or payload, missing
|
|
// compression flag, wrong lengths, uncompressed forms, x + p, points on
|
|
// the curve outside the subgroup, cofactor torsion), each with the
|
|
// verdict of the reference recomputed here: the KeyGroup of the drand
|
|
// crypto schemes (G1 for pedersen-bls-unchained, G2 for
|
|
// bls-unchained-g1-rfc9380), whose UnmarshalBinary is FromCompressed of
|
|
// kilic, and Equal(Null()) for the identity, as profile.Validate uses it.
|
|
// - decode: encodings drawn from a fixed seed: multiples of the generators,
|
|
// their negations, one flipped bit, random x with the compression flag,
|
|
// and random x of points on the curve outside the subgroup; each with the
|
|
// verdict, and for an invalid one the class of the error of kilic
|
|
// ("format", "curve" or "subgroup").
|
|
// - add, multiply: sums and multiples of points drawn from the seed, the
|
|
// special cases included (P + P, P + (-P), the point at infinity, the
|
|
// scalars 0, 1, r - 1, r, r + 1 and 2^256 - 1), computed by kilic.
|
|
// - pairing: e(P, Q) for points drawn from the seed, serialized by
|
|
// kyber-bls12381 (the order of kilic: c1 before c0 at every level).
|
|
// - hash_to_g1: HashToCurve of kilic for the DST of Quicknet and of tlock
|
|
// (BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_) on messages drawn from
|
|
// the seed and on the identities of some rounds, and for the DST of the
|
|
// test vectors of RFC 9380, appendix J.9.1, on their messages, with the
|
|
// affine coordinates.
|
|
// - map_to_g1: MapToCurve of kilic (the simplified SWU map, the isogeny and
|
|
// the clearing of the cofactor) on elements u drawn from the seed and on
|
|
// the exceptional ones, u = 0 and Z·u² = -1, which no hash reaches.
|
|
// - signatures: BLS signatures on G1 of kyber's sign/bls (NewSchemeOnG1,
|
|
// the scheme of Quicknet) under keys drawn from the seed, and the verdict
|
|
// of its Verify on each and on edited copies.
|
|
//
|
|
// The seed is fixed: the output is the same on every run. Run it in the
|
|
// module of the reference implementation, which it imports, without changing
|
|
// anything there, from the datekeys-go next to this repository: at the tag
|
|
// spec-v0.11 or at the draft v0.12, whose packages that it uses are the
|
|
// same, and so is the output.
|
|
//
|
|
// cd ../datekeys-go && go run ../datekeys-dart/tool/bls12381_go_vectors.go \
|
|
// ../datekeys-ts/src/lib/dkc/testing/bls12381-vectors.json \
|
|
// > ../datekeys-dart/test/vectors/bls12381_vectors.json
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"runtime/debug"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/drand/drand/v2/common"
|
|
"github.com/drand/drand/v2/crypto"
|
|
"github.com/drand/kyber"
|
|
bls "github.com/drand/kyber-bls12381"
|
|
signbls "github.com/drand/kyber/sign/bls"
|
|
bls12381 "github.com/kilic/bls12-381"
|
|
)
|
|
|
|
const quicknetDST = "BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_NUL_"
|
|
|
|
var (
|
|
p, _ = new(big.Int).SetString("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16)
|
|
order, _ = new(big.Int).SetString("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 16)
|
|
g1 = bls12381.NewG1()
|
|
g2 = bls12381.NewG2()
|
|
)
|
|
|
|
func must[T any](v T, err error) T {
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return v
|
|
}
|
|
|
|
// stream is a deterministic byte source: SHA-256 of the label, a counter
|
|
// and a block index.
|
|
type stream struct {
|
|
label string
|
|
n uint32
|
|
}
|
|
|
|
func (s *stream) bytes(n int) []byte {
|
|
s.n++
|
|
var out []byte
|
|
for i := uint32(0); len(out) < n; i++ {
|
|
h := sha256.Sum256(binary.BigEndian.AppendUint32(binary.BigEndian.AppendUint32([]byte("DateKeys BLS12-381 vectors "+s.label), s.n), i))
|
|
out = append(out, h[:]...)
|
|
}
|
|
return out[:n]
|
|
}
|
|
|
|
// scalar is a nonzero scalar below r.
|
|
func (s *stream) scalar() *big.Int {
|
|
k := new(big.Int).SetBytes(s.bytes(64))
|
|
k.Mod(k, new(big.Int).Sub(order, big.NewInt(1)))
|
|
return k.Add(k, big.NewInt(1))
|
|
}
|
|
|
|
func (s *stream) fp() *big.Int {
|
|
x := new(big.Int).SetBytes(s.bytes(64))
|
|
return x.Mod(x, p)
|
|
}
|
|
|
|
func fp48(x *big.Int) []byte { return x.FillBytes(make([]byte, 48)) }
|
|
|
|
func hx(b []byte) string { return hex.EncodeToString(b) }
|
|
|
|
func g1Mul(k *big.Int) *bls12381.PointG1 {
|
|
return g1.MulScalarBig(g1.New(), g1.One(), k)
|
|
}
|
|
|
|
func g2Mul(k *big.Int) *bls12381.PointG2 {
|
|
return g2.MulScalarBig(g2.New(), g2.One(), k)
|
|
}
|
|
|
|
func g1Enc(q *bls12381.PointG1) []byte { return g1.ToCompressed(g1.New().Set(q)) }
|
|
|
|
func g2Enc(q *bls12381.PointG2) []byte { return g2.ToCompressed(g2.New().Set(q)) }
|
|
|
|
// errorClass names the check of FromCompressed of kilic that failed.
|
|
func errorClass(err error) string {
|
|
switch {
|
|
case strings.Contains(err.Error(), "not on curve"):
|
|
return "curve"
|
|
case strings.Contains(err.Error(), "correct subgroup"):
|
|
return "subgroup"
|
|
default:
|
|
return "format"
|
|
}
|
|
}
|
|
|
|
type decodeVector struct {
|
|
Label string `json:"label"`
|
|
Group string `json:"group"`
|
|
Hex string `json:"hex"`
|
|
Go string `json:"go"`
|
|
Class string `json:"class,omitempty"`
|
|
}
|
|
|
|
func verdict(group string, b []byte) decodeVector {
|
|
v := decodeVector{Group: group, Hex: hx(b)}
|
|
var err error
|
|
var zero bool
|
|
if group == "G1" {
|
|
var q *bls12381.PointG1
|
|
if q, err = g1.FromCompressed(b); err == nil {
|
|
zero = g1.IsZero(q)
|
|
}
|
|
} else {
|
|
var q *bls12381.PointG2
|
|
if q, err = g2.FromCompressed(b); err == nil {
|
|
zero = g2.IsZero(q)
|
|
}
|
|
}
|
|
switch {
|
|
case err != nil:
|
|
v.Go, v.Class = "invalid", errorClass(err)
|
|
case zero:
|
|
v.Go = "identity"
|
|
default:
|
|
v.Go = "point"
|
|
}
|
|
return v
|
|
}
|
|
|
|
// schemeVerdict is the verdict of the KeyGroup of the drand scheme, as
|
|
// scripts/bls12381-go-verdicts.go of datekeys-ts computes it.
|
|
func schemeVerdict(group string, b []byte) string {
|
|
id := crypto.UnchainedSchemeID
|
|
if group == "G2" {
|
|
id = crypto.SigsOnG1ID
|
|
}
|
|
s := must(crypto.SchemeFromName(id))
|
|
k := s.KeyGroup.Point()
|
|
switch {
|
|
case k.UnmarshalBinary(b) != nil:
|
|
return "invalid"
|
|
case k.Equal(k.Null()):
|
|
return "identity"
|
|
default:
|
|
return "point"
|
|
}
|
|
}
|
|
|
|
type addVector struct {
|
|
Label string `json:"label"`
|
|
Group string `json:"group"`
|
|
A string `json:"a"`
|
|
B string `json:"b"`
|
|
Sum string `json:"sum"`
|
|
}
|
|
|
|
type mulVector struct {
|
|
Label string `json:"label"`
|
|
Group string `json:"group"`
|
|
Point string `json:"point"`
|
|
Scalar string `json:"scalar"`
|
|
Product string `json:"product"`
|
|
}
|
|
|
|
type pairingVector struct {
|
|
Label string `json:"label"`
|
|
G1 string `json:"g1"`
|
|
G2 string `json:"g2"`
|
|
GT string `json:"gt"`
|
|
}
|
|
|
|
type hashVector struct {
|
|
Label string `json:"label"`
|
|
DST string `json:"dst"`
|
|
Msg string `json:"msg"`
|
|
Point string `json:"point"`
|
|
X string `json:"x"`
|
|
Y string `json:"y"`
|
|
}
|
|
|
|
type mapVector struct {
|
|
Label string `json:"label"`
|
|
U string `json:"u"`
|
|
Point string `json:"point"`
|
|
}
|
|
|
|
type signatureVector struct {
|
|
Label string `json:"label"`
|
|
PublicKey string `json:"public_key"`
|
|
Msg string `json:"msg"`
|
|
Signature string `json:"signature"`
|
|
Go bool `json:"go"`
|
|
}
|
|
|
|
func main() {
|
|
out := struct {
|
|
Description string `json:"description"`
|
|
Generator string `json:"generator"`
|
|
Libraries string `json:"libraries"`
|
|
PointsFrom string `json:"points_from"`
|
|
Points []decodeVector `json:"points"`
|
|
Decode []decodeVector `json:"decode"`
|
|
Add []addVector `json:"add"`
|
|
Multiply []mulVector `json:"multiply"`
|
|
Pairing []pairingVector `json:"pairing"`
|
|
HashToG1 []hashVector `json:"hash_to_g1"`
|
|
MapToG1 []mapVector `json:"map_to_g1"`
|
|
Signatures []signatureVector `json:"signatures"`
|
|
}{
|
|
Description: "Go reference values for the BLS12-381 code of lib/src/bls12381_*.dart: decoding verdicts, " +
|
|
"sums, multiples, pairings, hashes to G1 and BLS signatures on G1; see tool/bls12381_go_vectors.go.",
|
|
Generator: "tool/bls12381_go_vectors.go",
|
|
Libraries: libraries(),
|
|
PointsFrom: "the encodings of src/lib/dkc/testing/bls12381-vectors.json of datekeys-ts at 289fe71, " +
|
|
"with the verdicts recomputed by this generator",
|
|
}
|
|
|
|
// The frozen edge cases of datekeys-ts.
|
|
var frozen struct {
|
|
Vectors []struct{ Label, Group, Hex, Go string }
|
|
}
|
|
if err := json.Unmarshal(must(os.ReadFile(os.Args[1])), &frozen); err != nil {
|
|
panic(err)
|
|
}
|
|
for _, f := range frozen.Vectors {
|
|
b := must(hex.DecodeString(f.Hex))
|
|
v := verdict(f.Group, b)
|
|
if (len(b) == 48 && f.Group == "G1") || (len(b) == 96 && f.Group == "G2") {
|
|
if s := schemeVerdict(f.Group, b); s != v.Go {
|
|
panic(f.Label + ": kilic and the drand scheme disagree")
|
|
}
|
|
} else {
|
|
v.Go, v.Class = schemeVerdict(f.Group, b), "format"
|
|
}
|
|
if v.Go != f.Go {
|
|
panic(f.Label + ": the verdict of datekeys-ts is not the one of Go")
|
|
}
|
|
v.Label = f.Label
|
|
out.Points = append(out.Points, v)
|
|
}
|
|
|
|
// Decoding.
|
|
s := &stream{label: "decode"}
|
|
for i := 0; i < 24; i++ {
|
|
b := g1Enc(g1Mul(s.scalar()))
|
|
neg := bytes.Clone(b)
|
|
neg[0] ^= 0x20
|
|
flip := bytes.Clone(b)
|
|
bit := 3 + int(binary.BigEndian.Uint16(s.bytes(2)))%(48*8-3)
|
|
flip[bit/8] ^= 0x80 >> (bit % 8)
|
|
for j, c := range [][]byte{b, neg, flip} {
|
|
v := verdict("G1", c)
|
|
v.Label = fmt.Sprintf("G1 multiple %d, %s", i, []string{"as encoded", "negated", fmt.Sprintf("bit %d flipped", bit)}[j])
|
|
out.Decode = append(out.Decode, v)
|
|
}
|
|
}
|
|
for i := 0; i < 8; i++ {
|
|
b := g2Enc(g2Mul(s.scalar()))
|
|
neg := bytes.Clone(b)
|
|
neg[0] ^= 0x20
|
|
flip := bytes.Clone(b)
|
|
bit := 3 + int(binary.BigEndian.Uint16(s.bytes(2)))%(96*8-3)
|
|
flip[bit/8] ^= 0x80 >> (bit % 8)
|
|
for j, c := range [][]byte{b, neg, flip} {
|
|
v := verdict("G2", c)
|
|
v.Label = fmt.Sprintf("G2 multiple %d, %s", i, []string{"as encoded", "negated", fmt.Sprintf("bit %d flipped", bit)}[j])
|
|
out.Decode = append(out.Decode, v)
|
|
}
|
|
}
|
|
// Random x, with the compression flag and either sign: on the curve or
|
|
// not, and then outside the subgroup.
|
|
classes := map[string]int{}
|
|
for i := 0; classes["G1 subgroup"] < 16 || classes["G1 curve"] < 8; i++ {
|
|
b := fp48(s.fp())
|
|
b[0] |= 0x80 | s.bytes(1)[0]&0x20
|
|
v := verdict("G1", b)
|
|
key := "G1 " + v.Class
|
|
if classes[key] >= 16 {
|
|
continue
|
|
}
|
|
classes[key]++
|
|
v.Label = fmt.Sprintf("G1 random x %d", i)
|
|
out.Decode = append(out.Decode, v)
|
|
}
|
|
for i := 0; classes["G2 subgroup"] < 8 || classes["G2 curve"] < 4; i++ {
|
|
b := append(fp48(s.fp()), fp48(s.fp())...)
|
|
b[0] |= 0x80 | s.bytes(1)[0]&0x20
|
|
v := verdict("G2", b)
|
|
key := "G2 " + v.Class
|
|
if classes[key] >= 8 {
|
|
continue
|
|
}
|
|
classes[key]++
|
|
v.Label = fmt.Sprintf("G2 random x %d", i)
|
|
out.Decode = append(out.Decode, v)
|
|
}
|
|
|
|
// Sums.
|
|
s = &stream{label: "add"}
|
|
inf1, inf2 := g1.Zero(), g2.Zero()
|
|
for i := 0; i < 16; i++ {
|
|
a, b := g1Mul(s.scalar()), g1Mul(s.scalar())
|
|
out.Add = append(out.Add, addVector{fmt.Sprintf("G1 sum %d", i), "G1", hx(g1Enc(a)), hx(g1Enc(b)), hx(g1Enc(g1.Add(g1.New(), a, b)))})
|
|
}
|
|
a1 := g1Mul(s.scalar())
|
|
for _, c := range []struct {
|
|
label string
|
|
a, b *bls12381.PointG1
|
|
}{
|
|
{"G1 P + P", a1, a1},
|
|
{"G1 P + (-P)", a1, g1.Neg(g1.New(), a1)},
|
|
{"G1 P + infinity", a1, inf1},
|
|
{"G1 infinity + P", inf1, a1},
|
|
{"G1 infinity + infinity", inf1, inf1},
|
|
} {
|
|
out.Add = append(out.Add, addVector{c.label, "G1", hx(g1Enc(c.a)), hx(g1Enc(c.b)), hx(g1Enc(g1.Add(g1.New(), c.a, c.b)))})
|
|
}
|
|
for i := 0; i < 8; i++ {
|
|
a, b := g2Mul(s.scalar()), g2Mul(s.scalar())
|
|
out.Add = append(out.Add, addVector{fmt.Sprintf("G2 sum %d", i), "G2", hx(g2Enc(a)), hx(g2Enc(b)), hx(g2Enc(g2.Add(g2.New(), a, b)))})
|
|
}
|
|
a2 := g2Mul(s.scalar())
|
|
for _, c := range []struct {
|
|
label string
|
|
a, b *bls12381.PointG2
|
|
}{
|
|
{"G2 P + P", a2, a2},
|
|
{"G2 P + (-P)", a2, g2.Neg(g2.New(), a2)},
|
|
{"G2 P + infinity", a2, inf2},
|
|
{"G2 infinity + P", inf2, a2},
|
|
} {
|
|
out.Add = append(out.Add, addVector{c.label, "G2", hx(g2Enc(c.a)), hx(g2Enc(c.b)), hx(g2Enc(g2.Add(g2.New(), c.a, c.b)))})
|
|
}
|
|
|
|
// Multiples.
|
|
s = &stream{label: "multiply"}
|
|
max256 := new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
|
|
special := []struct {
|
|
label string
|
|
k *big.Int
|
|
}{
|
|
{"0", big.NewInt(0)},
|
|
{"1", big.NewInt(1)},
|
|
{"2", big.NewInt(2)},
|
|
{"r - 1", new(big.Int).Sub(order, big.NewInt(1))},
|
|
{"r", new(big.Int).Set(order)},
|
|
{"r + 1", new(big.Int).Add(order, big.NewInt(1))},
|
|
{"2^256 - 1", max256},
|
|
}
|
|
for i := 0; i < 12; i++ {
|
|
q, k := g1Mul(s.scalar()), new(big.Int).SetBytes(s.bytes(32))
|
|
out.Multiply = append(out.Multiply, mulVector{fmt.Sprintf("G1 multiple %d", i), "G1", hx(g1Enc(q)), k.Text(16), hx(g1Enc(g1.MulScalarBig(g1.New(), q, k)))})
|
|
}
|
|
q1 := g1Mul(s.scalar())
|
|
for _, c := range special {
|
|
out.Multiply = append(out.Multiply, mulVector{"G1 by " + c.label, "G1", hx(g1Enc(q1)), c.k.Text(16), hx(g1Enc(g1.MulScalarBig(g1.New(), q1, c.k)))})
|
|
}
|
|
for i := 0; i < 6; i++ {
|
|
q, k := g2Mul(s.scalar()), new(big.Int).SetBytes(s.bytes(32))
|
|
out.Multiply = append(out.Multiply, mulVector{fmt.Sprintf("G2 multiple %d", i), "G2", hx(g2Enc(q)), k.Text(16), hx(g2Enc(g2.MulScalarBig(g2.New(), q, k)))})
|
|
}
|
|
q2 := g2Mul(s.scalar())
|
|
for _, c := range special {
|
|
out.Multiply = append(out.Multiply, mulVector{"G2 by " + c.label, "G2", hx(g2Enc(q2)), c.k.Text(16), hx(g2Enc(g2.MulScalarBig(g2.New(), q2, c.k)))})
|
|
}
|
|
|
|
// Pairings, through kyber-bls12381.
|
|
s = &stream{label: "pairing"}
|
|
suite := bls.NewBLS12381Suite()
|
|
for i := 0; i < 6; i++ {
|
|
a := suite.G1().Point().Mul(scalarOf(s.scalar()), nil)
|
|
b := suite.G2().Point().Mul(scalarOf(s.scalar()), nil)
|
|
out.Pairing = append(out.Pairing, pairingVector{fmt.Sprintf("e(P, Q) %d", i), marshal(a), marshal(b), marshal(suite.Pair(a, b))})
|
|
}
|
|
{
|
|
a := suite.G1().Point().Mul(scalarOf(s.scalar()), nil)
|
|
b := suite.G2().Point().Mul(scalarOf(s.scalar()), nil)
|
|
out.Pairing = append(out.Pairing,
|
|
pairingVector{"e(infinity, Q)", marshal(suite.G1().Point().Null()), marshal(b), marshal(suite.Pair(suite.G1().Point().Null(), b))},
|
|
pairingVector{"e(P, infinity)", marshal(a), marshal(suite.G2().Point().Null()), marshal(suite.Pair(a, suite.G2().Point().Null()))})
|
|
}
|
|
|
|
// Hashes to G1.
|
|
s = &stream{label: "hash"}
|
|
hashOne := func(label, dst string, msg []byte) hashVector {
|
|
q := must(g1.HashToCurve(msg, []byte(dst)))
|
|
u := g1.ToUncompressed(g1.New().Set(q))
|
|
return hashVector{label, dst, hx(msg), hx(g1Enc(q)), hx(u[:48]), hx(u[48:])}
|
|
}
|
|
for i := 0; i < 24; i++ {
|
|
n := int(s.bytes(1)[0]) % 80
|
|
out.HashToG1 = append(out.HashToG1, hashOne(fmt.Sprintf("a message of %d bytes", n), quicknetDST, s.bytes(n)))
|
|
}
|
|
sch := must(crypto.SchemeFromName(crypto.SigsOnG1ID))
|
|
for _, round := range []uint64{1, 1000, 1001, 1004, 2000, 83903165811, 1<<53 - 1} {
|
|
id := sch.DigestBeacon(&common.Beacon{Round: round})
|
|
out.HashToG1 = append(out.HashToG1, hashOne(fmt.Sprintf("the identity of round %d", round), quicknetDST, id))
|
|
}
|
|
const rfcDST = "QUUX-V01-CS02-with-BLS12381G1_XMD:SHA-256_SSWU_RO_"
|
|
for _, m := range []string{"", "abc", "abcdef0123456789", "q128_" + strings.Repeat("q", 128), "a512_" + strings.Repeat("a", 512)} {
|
|
out.HashToG1 = append(out.HashToG1, hashOne(fmt.Sprintf("RFC 9380 J.9.1, msg %q", shorten(m)), rfcDST, []byte(m)))
|
|
}
|
|
|
|
// The map to G1 of one element.
|
|
s = &stream{label: "map"}
|
|
z := big.NewInt(11)
|
|
// Z·u² = -1: u² = -1/Z, a square since -Z is one.
|
|
minusInvZ := new(big.Int).Sub(p, new(big.Int).ModInverse(z, p))
|
|
root := new(big.Int).ModSqrt(minusInvZ, p)
|
|
if root == nil {
|
|
panic("-1/Z is not a square")
|
|
}
|
|
us := []struct {
|
|
label string
|
|
u *big.Int
|
|
}{
|
|
{"u = 0, exceptional", big.NewInt(0)},
|
|
{"Z·u² = -1, exceptional", root},
|
|
{"Z·u² = -1, the other root, exceptional", new(big.Int).Sub(p, root)},
|
|
{"u = 1", big.NewInt(1)},
|
|
{"u = p - 1", new(big.Int).Sub(p, big.NewInt(1))},
|
|
}
|
|
for i := 0; i < 8; i++ {
|
|
us = append(us, struct {
|
|
label string
|
|
u *big.Int
|
|
}{fmt.Sprintf("u drawn from the seed %d", i), s.fp()})
|
|
}
|
|
for _, c := range us {
|
|
q := must(g1.MapToCurve(fp48(c.u)))
|
|
out.MapToG1 = append(out.MapToG1, mapVector{c.label, hx(fp48(c.u)), hx(g1Enc(q))})
|
|
}
|
|
|
|
// BLS signatures on G1, the scheme of Quicknet.
|
|
s = &stream{label: "signatures"}
|
|
scheme := signbls.NewSchemeOnG1(suite)
|
|
for i := 0; i < 6; i++ {
|
|
sk := scalarOf(s.scalar())
|
|
pk := suite.G2().Point().Mul(sk, nil)
|
|
msg := s.bytes(32)
|
|
sig := must(scheme.Sign(sk, msg))
|
|
other := s.bytes(32)
|
|
for _, c := range []struct {
|
|
label string
|
|
msg, sig []byte
|
|
}{
|
|
{fmt.Sprintf("signature %d", i), msg, sig},
|
|
{fmt.Sprintf("signature %d of another message", i), other, sig},
|
|
{fmt.Sprintf("signature %d negated", i), msg, negate(sig)},
|
|
} {
|
|
out.Signatures = append(out.Signatures, signatureVector{c.label, marshal(pk), hx(c.msg), hx(c.sig), scheme.Verify(pk, c.msg, c.sig) == nil})
|
|
}
|
|
}
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
enc.SetEscapeHTML(false)
|
|
if err := enc.Encode(out); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func scalarOf(k *big.Int) kyber.Scalar {
|
|
return bls.NewKyberScalar().SetBytes(k.FillBytes(make([]byte, 32)))
|
|
}
|
|
|
|
func marshal(m interface{ MarshalBinary() ([]byte, error) }) string {
|
|
return hex.EncodeToString(must(m.MarshalBinary()))
|
|
}
|
|
|
|
func negate(sig []byte) []byte {
|
|
c := bytes.Clone(sig)
|
|
c[0] ^= 0x20
|
|
return c
|
|
}
|
|
|
|
func shorten(m string) string {
|
|
if len(m) > 20 {
|
|
return m[:20] + "…"
|
|
}
|
|
return m
|
|
}
|
|
|
|
// libraries names the versions of the libraries this program ran with.
|
|
func libraries() string {
|
|
info, ok := debug.ReadBuildInfo()
|
|
if !ok {
|
|
panic("no build info")
|
|
}
|
|
var out []string
|
|
for _, d := range info.Deps {
|
|
switch d.Path {
|
|
case "github.com/kilic/bls12-381", "github.com/drand/kyber", "github.com/drand/kyber-bls12381", "github.com/drand/drand/v2":
|
|
out = append(out, d.Path+" "+d.Version)
|
|
}
|
|
}
|
|
sort.Strings(out)
|
|
return strings.Join(out, ", ")
|
|
}
|