Browse Source

Alignment with dalek

bulletproofs
Sarah Jamie Lewis 3 years ago
parent
commit
daa05d97c8
  1. 8
      primitives/bulletproofs/constaint_system_test.go
  2. 4
      primitives/bulletproofs/generators.go
  3. 49
      primitives/bulletproofs/inner_product.go
  4. 80
      primitives/bulletproofs/range_proof.go
  5. 124
      primitives/bulletproofs/range_proof_test.go
  6. 28
      primitives/core/transcript.go

8
primitives/bulletproofs/constaint_system_test.go

@ -20,11 +20,11 @@ func TestConstraintSystem(t *testing.T) {
b := new(ristretto.Scalar)
b.FromUniformBytes(bbytes[:])
xbytes := sha512.Sum512([]byte("a"))
xbytes := sha512.Sum512([]byte("b"))
x := new(ristretto.Scalar)
x.FromUniformBytes(xbytes[:])
ybytes := sha512.Sum512([]byte("b"))
ybytes := sha512.Sum512([]byte("a"))
y := new(ristretto.Scalar)
y.FromUniformBytes(ybytes[:])
@ -83,8 +83,8 @@ func TestConstraintSystemMix(t *testing.T) {
V1, a_lc := cs.Commit(three, prng.Next())
V2, b_lc := cs.Commit(three, prng.Next())
V3, x_lc := cs.Commit(four, prng.Next())
V4, y_lc := cs.Commit(two, prng.Next())
V3, x_lc := cs.Commit(two, prng.Next())
V4, y_lc := cs.Commit(four, prng.Next())
// todo make this an actual verifier!
cs.VerifierCommit(V1)

4
primitives/bulletproofs/generators.go

@ -0,0 +1,4 @@
package bulletproofs
type Generator struct {
}

49
primitives/bulletproofs/inner_product.go

@ -2,10 +2,9 @@ package bulletproofs
import (
"cwtch.im/tapir/primitives/core"
"encoding/json"
"encoding/binary"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
ristretto "github.com/gtank/ristretto255"
"strconv"
)
// InnerProductProof encapsulates an inner product proof
@ -19,14 +18,14 @@ type InnerProductProof struct {
// ProveInnerProduct generates a proof for <a,b>, the inner product of a and b
func ProveInnerProduct(a, b core.ScalarVector, u *ristretto.Element, P *ristretto.Element, G, H core.GeneratorVector, transcript *core.Transcript) InnerProductProof {
n := len(a)
transcript.AddToTranscript("n", []byte(strconv.Itoa(n)))
transcript.AddToTranscript("dom-sep", []byte("ipp v1"))
nb := make([]byte, 8)
binary.LittleEndian.PutUint64(nb, uint64(n))
transcript.AddToTranscript("n", nb)
Lvec := core.PointVector{}
Rvec := core.PointVector{}
Gbytes, _ := json.Marshal(G)
transcript.AddToTranscript("G", Gbytes)
Hbytes, _ := json.Marshal(H)
transcript.AddToTranscript("H", Hbytes)
transcript.AddToTranscript("P'", []byte(P.String()))
for n != 1 {
np := n / 2
aL, aR := a[:np], a[np:]
@ -40,9 +39,9 @@ func ProveInnerProduct(a, b core.ScalarVector, u *ristretto.Element, P *ristrett
L := core.MultiExp(append(aL.Join(bR), cL), append(GR.Join(HL), u))
R := core.MultiExp(append(aR.Join(bL), cR), append(GL.Join(HR), u))
transcript.AddToTranscript("L", []byte(L.String()))
transcript.AddElementToTranscript("L", L)
Lvec = append(Lvec, L)
transcript.AddToTranscript("R", []byte(R.String()))
transcript.AddElementToTranscript("R", R)
Rvec = append(Rvec, R)
u := transcript.CommitToTranscriptScalar("u")
@ -64,16 +63,12 @@ func ProveInnerProduct(a, b core.ScalarVector, u *ristretto.Element, P *ristrett
P_.Add(P_, P)
P_.Add(P_, new(ristretto.Element).ScalarMult(new(ristretto.Scalar).Invert(x2), R))
P = P_
transcript.AddToTranscript("P'", []byte(P.String()))
//ranscript.AddToTranscript("P'", []byte(P.String()))
a = aL
b = bL
G = GL
H = HL
Gbytes, _ := json.Marshal(G)
transcript.AddToTranscript("G", Gbytes)
Hbytes, _ := json.Marshal(H)
transcript.AddToTranscript("H", Hbytes)
n = np
}
@ -82,21 +77,23 @@ func ProveInnerProduct(a, b core.ScalarVector, u *ristretto.Element, P *ristrett
// Verify checks the given inner product proof
func Verify(proof InnerProductProof, n int, u, P *ristretto.Element, G, H core.GeneratorVector, transcript *core.Transcript) bool {
transcript.AddToTranscript("n", []byte(strconv.Itoa(n)))
np := n / 2
Gbytes, _ := json.Marshal(G)
transcript.AddToTranscript("G", Gbytes)
Hbytes, _ := json.Marshal(H)
transcript.AddToTranscript("H", Hbytes)
transcript.AddToTranscript("P'", []byte(P.String()))
transcript.AddToTranscript("dom-sep", []byte("ipp v1"))
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(n))
transcript.AddToTranscript("n", b)
for i := range proof.L {
GL, GR := G[:np], G[np:]
HL, HR := H[:np], H[np:]
transcript.AddToTranscript("L", []byte(proof.L[i].String()))
transcript.AddToTranscript("R", []byte(proof.R[i].String()))
transcript.AddElementToTranscript("L", proof.L[i])
transcript.AddElementToTranscript("R", proof.R[i])
x := transcript.CommitToTranscriptScalar("u")
log.Debugf("L: %x\n", proof.L[i].Encode([]byte{}))
log.Debugf("R %x\n", proof.R[i].Encode([]byte{}))
log.Debugf("u: %x\n", x.Encode([]byte{}))
xinv := new(ristretto.Scalar)
xinv.Invert(x)
@ -110,14 +107,8 @@ func Verify(proof InnerProductProof, n int, u, P *ristretto.Element, G, H core.G
P_.Add(P_, P)
P_.Add(P_, new(ristretto.Element).ScalarMult(new(ristretto.Scalar).Invert(x2), proof.R[i]))
P = P_
transcript.AddToTranscript("P'", []byte(P.String()))
G = GL
H = HL
Gbytes, _ := json.Marshal(G)
transcript.AddToTranscript("G", Gbytes)
Hbytes, _ := json.Marshal(H)
transcript.AddToTranscript("H", Hbytes)
np = np / 2
}
c := new(ristretto.Scalar)

80
primitives/bulletproofs/range_proof.go

@ -3,6 +3,7 @@ package bulletproofs
import (
"crypto/rand"
"cwtch.im/tapir/primitives/core"
"encoding/binary"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
ristretto "github.com/gtank/ristretto255"
"math/big"
@ -18,7 +19,7 @@ type RangeProof struct {
InnerProduct *ristretto.Scalar
Mu *ristretto.Scalar
IPP InnerProductProof
V *ristretto.Element
V []*ristretto.Element
}
// CommitmentsParams encapsulates the commitment parameters for a given range proof
@ -57,6 +58,14 @@ func GenerateRangeProof(value int32, c CommitmentsParams, transcript *core.Trans
two.Add(one, one)
two_n := core.PowerVector(two, c.max)
transcript.AddToTranscript("dom-sep", []byte("rangeproof v1"))
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(c.max))
transcript.AddToTranscript("n", b)
b = make([]byte, 8)
binary.LittleEndian.PutUint64(b, 1)
transcript.AddToTranscript("m", b)
// Generate a prng to from this transcript and some external randomness
// We use this to generate the rest of our private scalars
// TODO: move to transcript
@ -73,11 +82,14 @@ func GenerateRangeProof(value int32, c CommitmentsParams, transcript *core.Trans
alpha := prng.Next()
vs := new(ristretto.Scalar)
b := make([]byte, 32)
b = make([]byte, 32)
copy(b, big.NewInt(int64(value)).Bytes())
vs.Decode(b)
V := core.MultiExp(core.ScalarVector{gamma, vs}, core.GeneratorVector{c.h, c.g})
transcript.AddElementToTranscript("V", V)
A := core.MultiExp(append(aL.Join(aR), alpha), append(c.G.Join(c.H), c.h))
log.Debugf("vs: %v", vs)
@ -91,8 +103,8 @@ func GenerateRangeProof(value int32, c CommitmentsParams, transcript *core.Trans
S := core.MultiExp(append(Sl.Join(Sr), p), append(c.G.Join(c.H), c.h))
transcript.AddToTranscript("A", []byte(A.String()))
transcript.AddToTranscript("S", []byte(S.String()))
transcript.AddElementToTranscript("A", A)
transcript.AddElementToTranscript("S", S)
y := transcript.CommitToTranscriptScalar("y")
z := transcript.CommitToTranscriptScalar("z")
@ -116,8 +128,8 @@ func GenerateRangeProof(value int32, c CommitmentsParams, transcript *core.Trans
T1 := core.MultiExp(core.ScalarVector{t1, tau1}, core.GeneratorVector{c.g, c.h})
T2 := core.MultiExp(core.ScalarVector{t2, tau2}, core.GeneratorVector{c.g, c.h})
transcript.AddToTranscript("T1", []byte(T1.String()))
transcript.AddToTranscript("T2", []byte(T2.String()))
transcript.AddElementToTranscript("T_1", T1)
transcript.AddElementToTranscript("T_2", T2)
x := transcript.CommitToTranscriptScalar("x")
@ -147,18 +159,26 @@ func GenerateRangeProof(value int32, c CommitmentsParams, transcript *core.Trans
P := core.MultiExp(l.Join(r), c.G.Join(H_))
log.Debugf("P: %v", P)
uP := new(ristretto.Element).Add(P, new(ristretto.Element).ScalarMult(iplr, c.u))
log.Debugf("uP: %v", uP)
ipp := ProveInnerProduct(l, r, c.u, new(ristretto.Element).Add(new(ristretto.Element).Zero(), uP), core.CopyVector(c.G), core.CopyVector(H_), transcript)
mu := new(ristretto.Scalar)
mu.Add(alpha, new(ristretto.Scalar).Multiply(p, x))
taux := new(ristretto.Scalar)
taux.Multiply(tau2, new(ristretto.Scalar).Multiply(x, x))
taux.Add(taux, new(ristretto.Scalar).Multiply(tau1, x))
taux.Add(taux, new(ristretto.Scalar).Multiply(z2, gamma))
mu := new(ristretto.Scalar)
mu.Add(alpha, new(ristretto.Scalar).Multiply(p, x))
return RangeProof{A, S, T1, T2, taux, iplr, mu, ipp, V}, gamma
transcript.AddToTranscript("t_x", iplr.Encode([]byte{}))
transcript.AddToTranscript("t_x_blinding", taux.Encode([]byte{}))
transcript.AddToTranscript("e_blinding", mu.Encode([]byte{}))
w := transcript.CommitToTranscriptScalar("w")
U := new(ristretto.Element).ScalarMult(w, c.g)
uP := new(ristretto.Element).Add(P, new(ristretto.Element).ScalarMult(iplr, U))
log.Debugf("uP: %v", uP)
ipp := ProveInnerProduct(l, r, U, new(ristretto.Element).Add(new(ristretto.Element).Zero(), uP), core.CopyVector(c.G), core.CopyVector(H_), transcript)
return RangeProof{A, S, T1, T2, taux, iplr, mu, ipp, []*ristretto.Element{V}}, gamma
}
// VerifyRangeProof returns true if the given proof passes all the checks for a given set of commitment parameters
@ -169,13 +189,32 @@ func VerifyRangeProof(proof RangeProof, c CommitmentsParams, transcript *core.Tr
two.Add(one, one)
two_n := core.PowerVector(two, c.max)
transcript.AddToTranscript("A", []byte(proof.A.String()))
transcript.AddToTranscript("S", []byte(proof.S.String()))
transcript.AddToTranscript("dom-sep", []byte("rangeproof v1"))
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(c.max))
transcript.AddToTranscript("n", b)
b = make([]byte, 8)
binary.LittleEndian.PutUint64(b, 1)
transcript.AddToTranscript("m", b)
for _, v := range proof.V {
transcript.AddElementToTranscript("V", v)
}
transcript.AddElementToTranscript("A", proof.A)
transcript.AddElementToTranscript("S", proof.S)
y := transcript.CommitToTranscriptScalar("y")
z := transcript.CommitToTranscriptScalar("z")
transcript.AddToTranscript("T1", []byte(proof.T1.String()))
transcript.AddToTranscript("T2", []byte(proof.T2.String()))
transcript.AddElementToTranscript("T_1", proof.T1)
transcript.AddElementToTranscript("T_2", proof.T2)
x := transcript.CommitToTranscriptScalar("x")
transcript.AddToTranscript("t_x", proof.InnerProduct.Encode([]byte{}))
transcript.AddToTranscript("t_x_blinding", proof.TauX.Encode([]byte{}))
transcript.AddToTranscript("e_blinding", proof.Mu.Encode([]byte{}))
log.Debugf("mu: %x", proof.Mu.Encode([]byte{}))
log.Debugf("x: %x", x.Encode([]byte{}))
y_n := core.PowerVector(y, c.max)
// generate h'
H_ := make(core.GeneratorVector, c.max)
@ -193,7 +232,7 @@ func VerifyRangeProof(proof RangeProof, c CommitmentsParams, transcript *core.Tr
x2 := new(ristretto.Scalar)
x2.Multiply(x, x)
rhs := core.MultiExp(core.ScalarVector{z2, delta(y_n, z, c.max), x, x2}, core.GeneratorVector{proof.V, c.g, proof.T1, proof.T2})
rhs := core.MultiExp(core.ScalarVector{z2, delta(y_n, z, c.max), x, x2}, core.GeneratorVector(proof.V).Join(core.GeneratorVector{c.g, proof.T1, proof.T2}))
log.Debugf("lhs: %v", lhs)
log.Debugf("rhs: %v", rhs)
log.Debugf("equal: %v", lhs.Equal(rhs))
@ -218,12 +257,15 @@ func VerifyRangeProof(proof RangeProof, c CommitmentsParams, transcript *core.Tr
Pl := new(ristretto.Element).Subtract(Pr, new(ristretto.Element).ScalarMult(proof.Mu, c.h))
// check inner product
uP := new(ristretto.Element).Add(Pl, new(ristretto.Element).ScalarMult(proof.InnerProduct, c.u))
w := transcript.CommitToTranscriptScalar("w")
U := new(ristretto.Element).ScalarMult(w, c.g)
uP := new(ristretto.Element).Add(Pl, new(ristretto.Element).ScalarMult(proof.InnerProduct, U))
log.Debugf("P: %v", Pl)
log.Debugf("uP: %v", uP)
return Verify(proof.IPP, c.max, c.u, new(ristretto.Element).Add(new(ristretto.Element).Zero(), uP), core.CopyVector(c.G), core.CopyVector(H_), transcript)
return Verify(proof.IPP, c.max, U, new(ristretto.Element).Add(new(ristretto.Element).Zero(), uP), core.CopyVector(c.G), core.CopyVector(H_), transcript)
}
return false
}

124
primitives/bulletproofs/range_proof_test.go

@ -2,8 +2,11 @@ package bulletproofs
import (
"cwtch.im/tapir/primitives/core"
"encoding/hex"
"encoding/json"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"github.com/gtank/ristretto255"
"golang.org/x/crypto/sha3"
"testing"
)
@ -24,3 +27,124 @@ func TestProove(t *testing.T) {
t.Fatalf("Failed to Verify Range Proof")
}
}
func byteToPoint(in []byte) *ristretto255.Element {
element := ristretto255.NewElement()
element.Decode(in)
return element
}
func byteToScalar(in []byte) *ristretto255.Scalar {
scalar := ristretto255.NewScalar()
scalar.Decode(in[0:32])
return scalar
}
func decodeInnerProduct(in []byte) *InnerProductProof {
num_elements := len(in) / 32
lg_n := (num_elements - 2) / 2
lvec := make(core.PointVector, lg_n)
rvec := make(core.PointVector, lg_n)
for i := 0; i < lg_n; i++ {
pos := 2 * i * 32
lvec[i] = byteToPoint(in[pos : pos+32])
rvec[i] = byteToPoint(in[pos+32 : pos+64])
}
pos := 2 * lg_n * 32
a := byteToScalar(in[pos : pos+32])
b := byteToScalar(in[pos+32 : pos+64])
return &InnerProductProof{lvec, rvec, a, b}
}
func TestDalek(t *testing.T) {
log.SetLevel(log.LevelDebug)
t.Logf("Testing dalek-cryptography bulletproofs test vector...")
rp, _ := hex.DecodeString("46b6ea8b6a9710c41c2622d4b353dbcf5f89afe8ed66c469f192bec19dc71d23c0442827f97fc9085a89caa87d294b0a21e7b8957732ec4951f6bf7d3aa2c66e7af3b7b956c7dcb3bed1223575a217a30642b603b6bf1d4138ed95e3458c524510b42c8d82958f40b447a84242b1ba1eeea54013f80bad643048eeb0b17c292a057cb6ae1c42338837c05eaa6336a17d60fa141204e015a1df15b28c1318c709d7eb35569cde89c0bf37eace54880a151498b38da54c6d739564f46f01b73601e518355ea06c9ef58a45fcb3baadbd1ac54e0838c471a6b91845f123d569fa0c46ef94471b7b826230e8576146beec08ac3e6683998815c576581f4c0e493433480f95f6495210636eaa2e32b577e1c363e35e522db85b18a56d57eb626f9e2b50578e0d7ee7b74b328e158b366bb9d117db725820a2fec3b1508212d75823345a801c0b602bfa05919d7e3bb8e71944587072badc363f334b08ba90d13e077ad24b82bacd51fc668d2b880daabd3b87e6bdc9584af66523026a30aadfc359283891bb65cca502f47421ffeee1fb5a5237bfa965b66a8b8ca5d6954f4f8222244c6a5340dc81e8d781d092cae2a763f185dd0b89965b1dd2506807b5d3e5a305fd9a68e60b91389dcffae6f85538713aa7ed272b8174e2f0b9730ebb6c464d06")
t.Logf("Deserializing dalek-cryptography bulletproofs test vector...%x", rp)
A := byteToPoint(rp[0:32])
S := byteToPoint(rp[32:64])
T1 := byteToPoint(rp[64:96])
T2 := byteToPoint(rp[96:128])
TX := byteToScalar(rp[128:160])
TX_blinding := byteToScalar(rp[160:192])
micro := byteToScalar(rp[192 : 192+32])
ipp := decodeInnerProduct(rp[192+32:])
vbytes := []string{
"90b0c2fe57934dff9f5396e135e7d72b82b3c5393e1843178918eb2cf28a5f3c",
"74256a3e2a7fe948210c4095195ae4db3e3498c6c5fddc2afb226c0f1e97e468",
"7e348def6d03dc7bcbe7e03736ca2898e2efa9f6ff8ae4ed1cb5252ec1744075",
"861859f5d4c14f5d6d7ad88dcf43c9a98064a7d8702ffc9bad9eba2ed766702a",
"4c09b1260c833fefe25b1c3d3becc80979beca5e864d57fcb410bb15c7ba5c14",
"08cf26bfdf2e6b731536f5e48b4c0ac7b5fc846d36aaa3fe0d28f07c207f0814",
"a6e2d1c2770333c9a8a5ac10d9eb28e8609d5954428261335b2fd6ff0e0e8d69",
"30beef3b58fd2c18dde771d5c77e32f8dc01361e284aef517bce54a5c74c4665",
}
V := make([]*ristretto255.Element, len(vbytes))
for i, v := range vbytes {
V[i] = ristretto255.NewElement()
vdec, _ := hex.DecodeString(v)
V[i].Decode(vdec)
}
rangeProof := RangeProof{A, S, T1, T2, TX_blinding, TX, micro, *ipp, V[0:1]}
json, _ := json.Marshal(rangeProof)
t.Logf("RangeProof: %s", json)
t.Logf("Deserialized Range Proof: %s", json)
t.Logf("Generating dalek-cryptography pedersen generators....")
params := CommitmentsParams{}
params.g = ristretto255.NewElement().Base()
params.h = ristretto255.NewElement()
h := sha3.Sum512(params.g.Encode([]byte{}))
params.h = ristretto255.NewElement().FromUniformBytes(h[:])
params.max = 8
params.G = make(core.GeneratorVector, params.max)
params.H = make(core.GeneratorVector, params.max)
labelG := []byte{'G', 0, 0, 0, 0}
shake := sha3.NewShake256()
shake.Write([]byte("GeneratorsChain"))
shake.Write(labelG[:])
labelH := []byte{'H', 0, 0, 0, 0}
shakeH := sha3.NewShake256()
shakeH.Write([]byte("GeneratorsChain"))
shakeH.Write(labelH[:])
t.Logf("Generating dalek-cryptography BP generators....")
for i := 0; i < 8; i++ {
b := make([]byte, 64)
shake.Read(b)
params.G[i] = ristretto255.NewElement()
params.G[i].FromUniformBytes(b)
//t.Logf("G: %x", params.G[i].Encode([]byte{}))
bH := make([]byte, 64)
shakeH.Read(bH)
params.H[i] = ristretto255.NewElement()
params.H[i].FromUniformBytes(bH)
// t.Logf("H: %x", params.H[i].Encode([]byte{}))
}
//t.Logf("parmas: %v", params)
verifierTranscript := core.NewTranscript("Deserialize-And-Verify Test")
t.Logf("Verification Result: %v", VerifyRangeProof(rangeProof, params, verifierTranscript))
t.Logf("Transcript: %s\n", verifierTranscript.OutputTranscriptToAudit())
}

28
primitives/core/transcript.go

@ -2,9 +2,9 @@ package core
import (
"fmt"
"github.com/gtank/merlin"
ristretto "github.com/gtank/ristretto255"
"golang.org/x/crypto/sha3"
"hash"
"io"
)
@ -18,15 +18,14 @@ import (
//
// At some point we might want to extend this to be compatible with Merlin transcripts, built on STROBE
type Transcript struct {
hash hash.Hash
transcript string
merlinTranscript *merlin.Transcript
transcript string
}
// NewTranscript creates a new Transcript with the given Label, the label should be unique to the application
func NewTranscript(label string) *Transcript {
transcript := new(Transcript)
transcript.hash = sha3.New512()
transcript.AddToTranscript("protocol", []byte(label))
transcript.merlinTranscript = merlin.NewTranscript(label)
return transcript
}
@ -35,7 +34,13 @@ func NewTranscript(label string) *Transcript {
func (t *Transcript) AddToTranscript(label string, b []byte) {
op := fmt.Sprintf("%s (%d) %x;", label, len(b), b)
t.transcript = fmt.Sprintf("%v\n%v", t.transcript, op)
t.hash.Write([]byte(op))
t.merlinTranscript.AppendMessage([]byte(label), b)
}
// AddElementToTranscript appends a value to the transcript with the given label
// This binds the given data to the label.
func (t *Transcript) AddElementToTranscript(label string, element *ristretto.Element) {
t.AddToTranscript(label, element.Encode([]byte{}))
}
// OutputTranscriptToAudit outputs a human-readable copy of the transcript so far.
@ -48,14 +53,13 @@ func (t Transcript) OutputTranscriptToAudit() string {
func (t *Transcript) NewProtocol(label string) {
op := fmt.Sprintf("---- new-protcol: %s ----", label)
t.transcript = fmt.Sprintf("%v\n%v", t.transcript, op)
t.hash.Write([]byte(op))
t.merlinTranscript.AppendMessage([]byte("protocol"), []byte(label))
}
// CommitToTranscript generates a challenge based on the current transcript, it also commits the challenge to the transcript.
func (t *Transcript) CommitToTranscript(label string) []byte {
t.AddToTranscript("commit", []byte(label))
b := t.hash.Sum([]byte{})
t.AddToTranscript(label, b)
//t.AddToTranscript("commit", []byte(label))
b := t.merlinTranscript.ExtractBytes([]byte(label), 64)
return b
}
@ -75,9 +79,7 @@ func (prng *PRNG) Next() *ristretto.Scalar {
// CommitToPRNG commits the label to the transcript and derives a PRNG from the transcript.
func (t *Transcript) CommitToPRNG(label string) PRNG {
t.AddToTranscript("commit-prng", []byte(label))
b := t.hash.Sum([]byte{})
t.AddToTranscript(label, b)
b := t.merlinTranscript.ExtractBytes([]byte(label), 64)
prng := sha3.NewShake256()
prng.Write(b)
return PRNG{prng: prng}

Loading…
Cancel
Save