89 lines
1.8 KiB
Go
89 lines
1.8 KiB
Go
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)
|
||
}
|
||
|