func (rh *RandHound) newSession(public abstract.Point, purpose string, time time.Time) (*Session, []byte, error) { buf := new(bytes.Buffer) pub, err := public.MarshalBinary() if err != nil { return nil, nil, err } if err = binary.Write(buf, binary.LittleEndian, pub); err != nil { return nil, nil, err } tm, err := time.MarshalBinary() if err != nil { return nil, nil, err } if err = binary.Write(buf, binary.LittleEndian, tm); err != nil { return nil, nil, err } if err = binary.Write(buf, binary.LittleEndian, []byte(purpose)); err != nil { return nil, nil, err } return &Session{ Fingerprint: pub, Purpose: purpose, Time: time}, rh.hash(buf.Bytes()), nil }
func (c *ownedCoder) ownerEncode(payload, payout []byte, p abstract.Point) { // XXX trap-encode // Pick a fresh random key with which to encrypt the payload key := make([]byte, c.keylen) c.random.XORKeyStream(key, key) // Encrypt the payload with it c.suite.Cipher(key).XORKeyStream(payout, payload) // Compute a MAC over the encrypted payload h := c.suite.Hash() h.Write(payout) mac := h.Sum(nil)[:c.maclen] // Combine the key and the MAC into the Point for this cell header hdr := append(key, mac...) if len(hdr) != p.PickLen() { panic("oops, length of key+mac turned out wrong") } mp, _ := c.suite.Point().Pick(hdr, c.random) // Add this to the blinding point we already computed to transmit. p.Add(p, mp) }
// HashKDF is a random map from G to Z_p, for use as the key derivation function (KDF) in the hash-based Verdict // construction func HashKDF(point abstract.Point) abstract.Secret { bytes, _ := point.MarshalBinary() cipher := Suite.Cipher(bytes) // This seems to be the only easy way to get outside data reliably in an abstract.Secret. return Suite.Secret().Pick(cipher) }
// Verify takes a signature issued by EdDSA.Sign and // return nil if it is a valid signature, or an error otherwise // Takes: // - public key used in signing // - msg is the message to sign // - sig is the signature return by EdDSA.Sign func Verify(public abstract.Point, msg, sig []byte) error { if len(sig) != 64 { return errors.New("Signature length invalid") } R := suite.Point() if err := R.UnmarshalBinary(sig[:32]); err != nil { return fmt.Errorf("R invalid point: %s", err) } s := suite.Scalar() s.UnmarshalBinary(sig[32:]) // reconstruct h = H(R || Public || Msg) Pbuff, err := public.MarshalBinary() if err != nil { return err } hash := sha512.New() hash.Write(sig[:32]) hash.Write(Pbuff) hash.Write(msg) h := suite.Scalar().SetBytes(hash.Sum(nil)) // reconstruct S == k*A + R S := suite.Point().Mul(nil, s) hA := suite.Point().Mul(public, h) RhA := suite.Point().Add(R, hA) if !RhA.Equal(S) { return errors.New("Recontructed S is not equal to signature") } return nil }
// Verifies that the 'message' is included in the signature and that it // is correct. // Message is your own hash, and reply contains the inclusion proof + signature // on the aggregated message func VerifySignature(suite abstract.Suite, reply *StampSignature, public abstract.Point, message []byte) bool { // Check if aggregate public key is correct if !public.Equal(reply.AggPublic) { dbg.Lvl1("Aggregate-public-key check: FAILED (maybe you have an outdated config file of the tree)") return false } // First check if the challenge is ok if err := VerifyChallenge(suite, reply); err != nil { dbg.Lvl1("Challenge-check: FAILED (", err, ")") return false } dbg.Lvl2("Challenge-check: OK") // Incorporate the timestamp in the message since the verification process // is done by reconstructing the challenge var b bytes.Buffer if err := binary.Write(&b, binary.LittleEndian, reply.Timestamp); err != nil { dbg.Lvl1("Error marshaling the timestamp for signature verification") return false } msg := append(b.Bytes(), []byte(reply.MerkleRoot)...) if err := VerifySchnorr(suite, msg, public, reply.Challenge, reply.Response); err != nil { dbg.Lvl1("Signature-check: FAILED (", err, ")") return false } dbg.Lvl2("Signature-check: OK") // finally check the proof if !proof.CheckProof(suite.Hash, reply.MerkleRoot, hashid.HashId(message), reply.Prf) { dbg.Lvl2("Inclusion-check: FAILED") return false } dbg.Lvl2("Inclusion-check: OK") return true }
// Checks the signature against // the message func SchnorrVerify(suite abstract.Suite, kp SchnorrPublicKey, msg []byte, sig []byte) (bool, error) { buf := bytes.NewBuffer(sig) signature := SchnorrSignature{} err := abstract.Read(buf, &signature, suite) if err != nil { return false, err } s := signature.S e := signature.E var gs, ye, r abstract.Point gs = suite.Point().Mul(nil, s) // g^s ye = suite.Point().Mul(kp.Y, e) // y^e r = suite.Point().Add(gs, ye) // g^xy^e r_bin, _ := r.MarshalBinary() msg_and_r := append(msg, r_bin...) hasher := sha3.New256() hasher.Write(msg_and_r) h := hasher.Sum(nil) // again I'm hoping this just reads the state out // and doesn't actually perform any ops lct := suite.Cipher(h) ev := suite.Secret().Pick(lct) return ev.Equal(e), nil }
// PointEncodeTo provides a generic implementation of Point.EncodeTo // based on Point.Encode. func PointMarshalTo(p abstract.Point, w io.Writer) (int, error) { buf, err := p.MarshalBinary() if err != nil { return 0, err } return w.Write(buf) }
func MarshalPoint(pt abstract.Point) []byte { buf := new(bytes.Buffer) ptByte := make([]byte, SecretSize) pt.MarshalTo(buf) buf.Read(ptByte) return ptByte }
/* Given a Diffie-Hellman shared public key, produces a secret to encrypt * another secret * * Arguments * diffieBase = the DH shared public key * * Return * the DH secret */ func (p *Deal) diffieHellmanSecret(diffieBase abstract.Point) abstract.Secret { buff, err := diffieBase.MarshalBinary() if err != nil { panic("Bad shared secret for Diffie-Hellman given.") } cipher := p.suite.Cipher(buff) return p.suite.Secret().Pick(cipher) }
/* Verifies that a PolicyApproveMessage has been properly constructed. * * Arguments: * su = the suite that the insurer's public key was derived from. * insuredKey = the public key of the insured or the client * insurerKey = the public key of the insurer or "trustee" * * Returns: * whether or not the message is valid. */ func (msg *PolicyApprovedMessage) verifyCertificate(su abstract.Suite, insuredKey abstract.Point) bool { set := anon.Set{msg.PubKey} _, err := anon.Verify(su, msg.Message, set, nil, msg.Signature) correctMsg := msg.PubKey.String() + " insures " + insuredKey.String() return err == nil && correctMsg == string(msg.Message) }
// NewServerIdentity creates a new ServerIdentity based on a public key and with a slice // of IP-addresses where to find that entity. The Id is based on a // version5-UUID which can include a URL that is based on it's public key. func NewServerIdentity(public abstract.Point, addresses ...string) *ServerIdentity { url := NamespaceURL + "id/" + public.String() return &ServerIdentity{ Public: public, Addresses: addresses, ID: ServerIdentityID(uuid.NewV5(uuid.NamespaceURL, url)), } }
// accommodate nils func (sn *Node) sub(a abstract.Point, b abstract.Point) { if a == nil { a = sn.suite.Point().Null() } if b != nil { a.Sub(a, b) } }
// Returns a hash of the message and the random secret: // H( m || V ) // Returns an error if something went wrong with the marshalling func (s *Schnorr) hashMessage(msg []byte, v abstract.Point) (abstract.Scalar, error) { vb, err := v.MarshalBinary() if err != nil { return nil, err } c := s.suite.Cipher(vb) c.Message(nil, nil, msg) return s.suite.Scalar().Pick(c), nil }
/* Adds a new connection to the connection manager * * Arguments: * theirkey = the key of the peer that this server wishes to connect to * * Returns: * An error denoting whether creating the new connection was successful. */ func (gcm *ChanConnManager) AddConn(theirKey abstract.Point) error { newConn, err := coconet.NewGoConn(gcm.dir, gcm.pubKey.String(), theirKey.String()) if err != nil { return err } gcm.peerMap[theirKey.String()] = newConn return nil }
func signH1pre(suite abstract.Suite, linkScope []byte, linkTag abstract.Point, message []byte) abstract.Cipher { H1pre := suite.Cipher(message) // m if linkScope != nil { H1pre.Write(linkScope) // L tag, _ := linkTag.MarshalBinary() H1pre.Write(tag) // ~y } return H1pre }
func (c *Coordinator) AddClient(key abstract.Point, val *net.UDPAddr) { // delete the client who has same ip address for k, v := range c.Clients { if v.String() == val.String() { delete(c.Clients, k) break } } c.Clients[key.String()] = val }
// (Either side) This function computes the shared public key // by adding public key points over the curve group. // Since each public key is already g*k where g is the group // generator this is all we need to do func SchnorrMComputeSharedPublicKey(suite abstract.Suite, pkeys []SchnorrPublicKey) SchnorrMultiSignaturePublicKey { var P abstract.Point = pkeys[0].Y for _, pkey := range pkeys[1:] { P.Add(P, pkey.Y) } return SchnorrMultiSignaturePublicKey{P} }
/* Creates a new policy-approved message * * Arguments: * kp = the private/public key of the insuring server. * theirKey = the public key of the server who requested the insurance * * Returns: * A new policy approved message. * * NOTE: * The approved certificate is a string of the form: * "My_Public_Key insures Their_Public_Key" * * It will always be of this form for easy validation. */ func (msg *PolicyApprovedMessage) createMessage(kp *config.KeyPair, theirKey abstract.Point) *PolicyApprovedMessage { set := anon.Set{kp.Public} approveMsg := kp.Public.String() + " insures " + theirKey.String() msg.PubKey = kp.Public msg.Message = []byte(approveMsg) msg.Signature = anon.Sign(kp.Suite, random.Stream, msg.Message, set, nil, 0, kp.Secret) return msg }
func signH1(suite abstract.Suite, H1pre abstract.Cipher, PG, PH abstract.Point) abstract.Secret { H1 := H1pre.Clone() PGb, _ := PG.MarshalBinary() H1.Write(PGb) if PH != nil { PHb, _ := PH.MarshalBinary() H1.Write(PHb) } H1.Message(nil, nil, nil) // finish message absorption return suite.Secret().Pick(H1) }
func hash(suite abstract.Suite, r abstract.Point, msg []byte) (abstract.Scalar, error) { rBuf, err := r.MarshalBinary() if err != nil { return nil, err } cipher := suite.Cipher(rBuf) cipher.Message(nil, nil, msg) // (re)compute challenge (e) e := suite.Scalar().Pick(cipher) return e, nil }
func (c *ownedCoder) inlineEncode(payload []byte, p abstract.Point) { // Hash the cleartext payload to produce the MAC h := c.suite.Hash() h.Write(payload) mac := h.Sum(nil)[:c.maclen] // Embed the payload and MAC into a Point representing the message hdr := append(payload, mac...) mp, _ := c.suite.Point().Pick(hdr, c.random) // Add this to the blinding point we already computed to transmit. p.Add(p, mp) }
// (Client side) The client requiring the n-signature scheme // performs the addition of points under the elliptic curve group // and returns the aggregate commitment as a raw point // in bytes for transmission to the server func SchnorrMComputeAggregateCommitment(suite abstract.Suite, pcommits []SchnorrMPublicCommitment) SchnorrMAggregateCommmitment { var P abstract.Point = pcommits[0].T for _, pcommit := range pcommits[1:] { P.Add(P, pcommit.T) } k := SchnorrMAggregateCommmitment{P} return k /*buf := bytes.Buffer{} abstract.Write(&buf, &k, suite) return buf.Bytes()*/ }
func ElGamalVerify(suite abstract.Suite, message []byte, publicKey abstract.Point, signatureBuffer []byte, g abstract.Point) error { // Decode the signature buf := bytes.NewBuffer(signatureBuffer) sig := basicSig{} if err := abstract.Read(buf, &sig, suite); err != nil { return err } r := sig.R c := sig.C // Compute base**(r + x*c) == T var P, T abstract.Point P = suite.Point() T = suite.Point() T.Add(T.Mul(g, r), P.Mul(publicKey, c)) // Verify that the hash based on the message and T // matches the challange c from the signature c = hashElGamal(suite, message, T) if !c.Equal(sig.C) { return errors.New("invalid signature") } return nil }
func EncryptKey(g abstract.Group, msgPt abstract.Point, pks []abstract.Point) (abstract.Point, abstract.Point) { k := g.Scalar().Pick(random.Stream) c1 := g.Point().Mul(nil, k) var c2 abstract.Point = nil for _, pk := range pks { if c2 == nil { c2 = g.Point().Mul(pk, k) } else { c2 = c2.Add(c2, g.Point().Mul(pk, k)) } } c2 = c2.Add(c2, msgPt) return c1, c2 }
func verifyCommitment(suite abstract.Suite, msg []byte, commitment abstract.Point, challenge abstract.Scalar) error { pb, err := commitment.MarshalBinary() if err != nil { return err } cipher := suite.Cipher(pb) cipher.Message(nil, nil, msg) // reconstructed challenge reconstructed := suite.Scalar().Pick(cipher) if !reconstructed.Equal(challenge) { return errors.New("Reconstructed challenge not equal to one given") } return nil }
func Encrypt(g abstract.Group, msg []byte, pks []abstract.Point) ([]abstract.Point, []abstract.Point) { c1s := []abstract.Point{} c2s := []abstract.Point{} var msgPt abstract.Point remainder := msg for len(remainder) != 0 { msgPt, remainder = g.Point().Pick(remainder, random.Stream) k := g.Scalar().Pick(random.Stream) c1 := g.Point().Mul(nil, k) var c2 abstract.Point = nil for _, pk := range pks { if c2 == nil { c2 = g.Point().Mul(pk, k) } else { c2 = c2.Add(c2, g.Point().Mul(pk, k)) } } c2 = c2.Add(c2, msgPt) c1s = append(c1s, c1) c2s = append(c2s, c2) } return c1s, c2s }
// PointDecodeFrom provides a generic implementation of Point.DecodeFrom, // based on Point.Decode, or Point.Pick if r is a Cipher or cipher.Stream. // The returned byte-count is valid only when decoding from a normal Reader, // not when picking from a pseudorandom source. func PointUnmarshalFrom(p abstract.Point, r io.Reader) (int, error) { if strm, ok := r.(cipher.Stream); ok { p.Pick(nil, strm) return -1, nil // no byte-count when picking randomly } buf := make([]byte, p.MarshalSize()) n, err := io.ReadFull(r, buf) if err != nil { return n, err } return n, p.UnmarshalBinary(buf) }
func ElGamalVerify(suite abstract.Suite, message []byte, publicKey abstract.Point, sig BasicSig) error { r := sig.R c := sig.C // Compute base**(r + x*c) == T var P, T abstract.Point P = suite.Point() T = suite.Point() T.Add(T.Mul(nil, r), P.Mul(publicKey, c)) // Verify that the hash based on the message and T // matches the challange c from the signature c = hashElGamal(suite, message, T) if !c.Equal(sig.C) { return errors.New("invalid signature") } return nil }
func SchnorrVerify(suite abstract.Suite, message []byte, signature net.BasicSignature) error { publicKey := signature.Pub r := signature.Resp c := signature.Chall // Compute base**(r + x*c) == T var P, T abstract.Point P = suite.Point() T = suite.Point() T.Add(T.Mul(nil, r), P.Mul(publicKey, c)) // Verify that the hash based on the message and T // matches the challange c from the signature c = hashSchnorr(suite, message, T) if !c.Equal(signature.Chall) { return errors.New("invalid signature") } return nil }
// Pick a [pseudo-]random curve point with optional embedded data, // filling in the point's x,y coordinates // and returning any remaining data not embedded. func (c *curve) pickPoint(P point, data []byte, rand cipher.Stream) []byte { // How much data to embed? dl := c.pickLen() if dl > len(data) { dl = len(data) } // Retry until we find a valid point var x, y nist.Int var Q abstract.Point for { // Get random bits the size of a compressed Point encoding, // in which the topmost bit is reserved for the x-coord sign. l := c.PointLen() b := make([]byte, l) rand.XORKeyStream(b, b) // Interpret as little-endian if data != nil { b[0] = byte(dl) // Encode length in low 8 bits copy(b[1:1+dl], data) // Copy in data to embed } util.Reverse(b, b) // Convert to big-endian form xsign := b[0] >> 7 // save x-coordinate sign bit b[0] &^= 0xff << uint(c.P.BitLen()&7) // clear high bits y.M = &c.P // set y-coordinate y.SetBytes(b) if !c.solveForX(&x, &y) { // Corresponding x-coordinate? continue // none, retry } // Pick a random sign for the x-coordinate if c.coordSign(&x) != uint(xsign) { x.Neg(&x) } // Initialize the point P.initXY(&x.V, &y.V, c.self) if c.full { // If we're using the full group, // we just need any point on the curve, so we're done. return data[dl:] } // We're using the prime-order subgroup, // so we need to make sure the point is in that subgroup. // If we're not trying to embed data, // we can convert our point into one in the subgroup // simply by multiplying it by the cofactor. if data == nil { P.Mul(P, &c.cofact) // multiply by cofactor if P.Equal(c.null) { continue // unlucky; try again } return data[dl:] } // Since we need the point's y-coordinate to make sense, // we must simply check if the point is in the subgroup // and retry point generation until it is. if Q == nil { Q = c.self.Point() } Q.Mul(P, &c.order) if Q.Equal(c.null) { return data[dl:] } // Keep trying... } }