summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/rsa.go35
-rw-r--r--lib/rsa_test.go24
2 files changed, 59 insertions, 0 deletions
diff --git a/lib/rsa.go b/lib/rsa.go
index 86df861..2c0769b 100644
--- a/lib/rsa.go
+++ b/lib/rsa.go
@@ -63,3 +63,38 @@ func egcd(a, b *big.Int) GCDResult {
Y: y,
}
}
+
+func invmod(a, n *big.Int) (*big.Int, error) {
+ // Initialize.
+ t0 := big.NewInt(0)
+ t1 := big.NewInt(1)
+ r0 := biCopy(big.NewInt(0), n)
+ r1 := biCopy(big.NewInt(0), a)
+
+ for r1.Cmp(big.NewInt(0)) != 0 {
+ q := big.NewInt(0)
+ q.Div(r0, r1)
+
+ tt := big.NewInt(0)
+ tt = tt.Mul(q, t1)
+ tt = tt.Sub(t0, tt)
+
+ biCopy(t0, t1)
+ biCopy(t1, tt)
+
+ tr := big.NewInt(0)
+ tr = tr.Mul(q, r1)
+ tr = tr.Sub(r0, tr)
+
+ biCopy(r0, r1)
+ biCopy(r1, tr)
+ }
+
+ if r0.Cmp(big.NewInt(1)) > 0 {
+ return nil, CPError{"not invertible"}
+ }
+ if t0.Cmp(big.NewInt(0)) < 0 {
+ t0.Add(t0, n)
+ }
+ return t0, nil
+}
diff --git a/lib/rsa_test.go b/lib/rsa_test.go
index ee71755..4f65468 100644
--- a/lib/rsa_test.go
+++ b/lib/rsa_test.go
@@ -50,3 +50,27 @@ func TestEGCD(t *testing.T) {
}
}
+
+func TestInvMod(t *testing.T) {
+ a := big.NewInt(17)
+ b := big.NewInt(3120)
+ e := big.NewInt(2753) // Expected inverse.
+ i, err := invmod(a, b)
+ if err != nil {
+ t.Errorf("invmod(%v,%v) failed: %v", a, b, err)
+ }
+ if i.Cmp(e) != 0 {
+ t.Errorf("gcd(%v,%v) != %v", a, b, e)
+ }
+
+ a = big.NewInt(240)
+ b = big.NewInt(47)
+ e = big.NewInt(19) // Expected inverse.
+ i, err = invmod(a, b)
+ if err != nil {
+ t.Errorf("invmod(%v,%v) failed: %v", a, b, err)
+ }
+ if i.Cmp(e) != 0 {
+ t.Errorf("gcd(%v,%v) != %v", a, b, e)
+ }
+}