mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 10:37:27 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	crand "crypto/rand"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/sharing"
 | 
						|
	"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/verenc/elgamal"
 | 
						|
)
 | 
						|
 | 
						|
func main() {
 | 
						|
	// Setup
 | 
						|
	curve := curves.ED25519()
 | 
						|
	serverPk, serverSk, _ := elgamal.NewKeys(curve)
 | 
						|
	aliceEk, _, _ := elgamal.NewKeys(curve)
 | 
						|
	bobEk, _, _ := elgamal.NewKeys(curve)
 | 
						|
 | 
						|
	signKey := curve.Scalar.Random(crand.Reader)
 | 
						|
	verKey := curve.ScalarBaseMult(signKey)
 | 
						|
 | 
						|
	shamir, _ := sharing.NewShamir(2, 2, curve)
 | 
						|
	shares, _ := shamir.Split(signKey, crand.Reader)
 | 
						|
 | 
						|
	// Create a proof s.t. Alice and Bob submit
 | 
						|
	// proofs of correctness for their ciphertexts
 | 
						|
	// Alice and Bob can decrypt their respective shares
 | 
						|
	// But the server cannot.
 | 
						|
	// The server checks whether the ciphertexts
 | 
						|
	// are valid encrypted shares
 | 
						|
	aliceDomain := []byte("alice_share")
 | 
						|
	bobDomain := []byte("bob_share")
 | 
						|
	aliceStuff := computeProof(curve, shares[0].Value, aliceDomain, aliceEk, serverPk)
 | 
						|
	bobStuff := computeProof(curve, shares[1].Value, bobDomain, bobEk, serverPk)
 | 
						|
 | 
						|
	if !verifyProof(curve, aliceStuff, aliceDomain, aliceEk, serverPk) {
 | 
						|
		panic("bad alice proof")
 | 
						|
	}
 | 
						|
	if !verifyProof(curve, bobStuff, bobDomain, bobEk, serverPk) {
 | 
						|
		panic("bad bob proof")
 | 
						|
	}
 | 
						|
	aliceShare, _ := aliceStuff.serverctxt.ToHomomorphicCipherText().Decrypt(serverSk)
 | 
						|
	bobShare, _ := bobStuff.serverctxt.ToHomomorphicCipherText().Decrypt(serverSk)
 | 
						|
 | 
						|
	avk := shamirCombinePoint(curve, []curves.Point{aliceShare, bobShare})
 | 
						|
	if avk.Equal(verKey) {
 | 
						|
		fmt.Println("Success")
 | 
						|
	} else {
 | 
						|
		fmt.Println("Failure")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func shamirCombinePoint(curve *curves.Curve, points []curves.Point) curves.Point {
 | 
						|
	result := curve.Point.Identity()
 | 
						|
 | 
						|
	for i, p := range points {
 | 
						|
		basis := curve.Scalar.One()
 | 
						|
		for j := range points {
 | 
						|
			if i == j {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			// x_m - x_j
 | 
						|
			denom := curve.Scalar.New(j + 1).Sub(curve.Scalar.New(i + 1))
 | 
						|
			if denom.IsZero() {
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
			// x_m / x_m - x_j
 | 
						|
			basis = basis.Mul(curve.Scalar.New(j + 1).Div(denom))
 | 
						|
		}
 | 
						|
 | 
						|
		result = result.Add(p.Mul(basis))
 | 
						|
	}
 | 
						|
 | 
						|
	return result
 | 
						|
}
 | 
						|
 | 
						|
func verifyProof(
 | 
						|
	curve *curves.Curve,
 | 
						|
	proof *commitTwinProof,
 | 
						|
	domain []byte,
 | 
						|
	encKey *elgamal.EncryptionKey,
 | 
						|
	serverPk *elgamal.EncryptionKey,
 | 
						|
) bool {
 | 
						|
	genBytes := append(domain, encKey.Value.ToAffineUncompressed()...)
 | 
						|
	genBytes = append(genBytes, proof.encctxt.Nonce...)
 | 
						|
	h := curve.NewGeneratorPoint().Hash(genBytes)
 | 
						|
 | 
						|
	w1 := curve.ScalarBaseMult(proof.d).Add(serverPk.Value.Mul(proof.d1)).Add(proof.serverctxt.C2.Mul(proof.c))
 | 
						|
	w2 := h.Mul(proof.d).Add(encKey.Value.Mul(proof.d2)).Add(proof.encctxt.C2.Mul(proof.c))
 | 
						|
	c := curve.NewScalar().Hash(append(w1.ToAffineCompressed(), w2.ToAffineCompressed()...))
 | 
						|
	return c.Cmp(proof.c) == 0
 | 
						|
}
 | 
						|
 | 
						|
type commitTwinProof struct {
 | 
						|
	c, d, d1, d2 curves.Scalar
 | 
						|
	serverctxt   *elgamal.CipherText
 | 
						|
	encctxt      *elgamal.CipherText
 | 
						|
}
 | 
						|
 | 
						|
func computeProof(
 | 
						|
	curve *curves.Curve,
 | 
						|
	share, domain []byte,
 | 
						|
	encKey *elgamal.EncryptionKey,
 | 
						|
	servKey *elgamal.EncryptionKey,
 | 
						|
) *commitTwinProof {
 | 
						|
	r1 := curve.Scalar.Random(crand.Reader)
 | 
						|
	r2 := curve.Scalar.Random(crand.Reader)
 | 
						|
	encctxt, _, _ := encKey.VerifiableEncrypt(share, &elgamal.EncryptParams{
 | 
						|
		Domain:          domain,
 | 
						|
		Blinding:        r2,
 | 
						|
		MessageIsHashed: true,
 | 
						|
		ProofNonce:      domain,
 | 
						|
	})
 | 
						|
	serverCtxt, _, _ := servKey.VerifiableEncrypt(share, &elgamal.EncryptParams{
 | 
						|
		Blinding:        r1,
 | 
						|
		MessageIsHashed: true,
 | 
						|
		ProofNonce:      domain,
 | 
						|
	})
 | 
						|
 | 
						|
	w := curve.Scalar.Random(crand.Reader)
 | 
						|
	n1 := curve.Scalar.Random(crand.Reader)
 | 
						|
	n2 := curve.Scalar.Random(crand.Reader)
 | 
						|
 | 
						|
	genBytes := append(domain, encKey.Value.ToAffineUncompressed()...)
 | 
						|
	genBytes = append(genBytes, encctxt.Nonce...)
 | 
						|
	h := curve.NewGeneratorPoint().Hash(genBytes)
 | 
						|
 | 
						|
	w1 := curve.ScalarBaseMult(w).Add(servKey.Value.Mul(n1))
 | 
						|
	w2 := h.Mul(w).Add(encKey.Value.Mul(n2))
 | 
						|
	c := curve.NewScalar().Hash(append(w1.ToAffineCompressed(), w2.ToAffineCompressed()...))
 | 
						|
	s, err := curve.NewScalar().SetBytes(share)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
	// d = w - c s
 | 
						|
	d := w.Sub(c.Mul(s))
 | 
						|
	// d1 = n1 - c r1
 | 
						|
	d1 := n1.Sub(c.Mul(r1))
 | 
						|
	// d2 = n2 - c r2
 | 
						|
	d2 := n2.Sub(c.Mul(r2))
 | 
						|
 | 
						|
	return &commitTwinProof{
 | 
						|
		c:          c,
 | 
						|
		d:          d,
 | 
						|
		d1:         d1,
 | 
						|
		d2:         d2,
 | 
						|
		encctxt:    encctxt,
 | 
						|
		serverctxt: serverCtxt,
 | 
						|
	}
 | 
						|
}
 |