party/internal/data/blind_sign_requests.go
2026-04-28 19:46:06 +02:00

89 lines
1.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package data
import (
"time"
"database/sql"
"encoding/pem"
"context"
"errors"
"fmt"
"math/big"
"crypto/rsa"
"crypto/x509"
)
type BlindSignRequest struct {
UserID int64 `json:"user_id"`
IssueID int64 `json:"issue_id"`
Created time.Time `json:"created"`
}
type BlindSignRequestModel struct {
DB *sql.DB
}
func (m BlindSignRequestModel) Insert(blind_sign *BlindSignRequest) error {
query := `
INSERT INTO blind_sign_requests (user_id, issue_id)
VALUES ($1, $2)
RETURNING created`
args := []interface{}{
blind_sign.UserID,
blind_sign.IssueID,
}
return m.DB.QueryRow(query, args...).Scan(
&blind_sign.Created,
)
}
func (m BlindSignRequestModel) BlindSign(issueID int64, blindedVoteBytes []byte) ([]byte, error) {
if issueID < 1 {
return nil, ErrRecordNotFound
}
query := `SELECT rsa_private_pem FROM issues WHERE id = $1`
ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
defer cancel()
var pemBytes []byte
err := m.DB.QueryRowContext(ctx, query, issueID).Scan(&pemBytes)
if err != nil {
switch {
case errors.Is(err, sql.ErrNoRows):
return nil, ErrRecordNotFound
default:
return nil, err
}
}
key, err := parsePrivateKey(pemBytes)
if err != nil {
return nil, fmt.Errorf("parse private key: %w", err)
}
m_ := new(big.Int).SetBytes(blindedVoteBytes)
// Validate range: m must be in [1, n-1]
one := big.NewInt(1)
if m_.Cmp(one) < 0 || m_.Cmp(key.N) >= 0 {
return nil, ErrInvalidBlindedVote
}
// s = m^d mod n
sig := new(big.Int).Exp(m_, key.D, key.N)
return sig.Bytes(), nil
}
func parsePrivateKey(pemBytes []byte) (*rsa.PrivateKey, error) {
block, _ := pem.Decode(pemBytes)
if block == nil {
return nil, errors.New("failed to decode PEM block")
}
return x509.ParsePKCS1PrivateKey(block.Bytes)
}