source: trunk/CrypPlugins/QuadraticSieve/QuadraticSieve.cs @ 1695

Last change on this file since 1695 was 1695, checked in by Sven Rech, 12 years ago

quadratic sieve fix

File size: 36.8 KB
Line 
1/*                             
2   Copyright 2009 Team CrypTool (Sven Rech,Dennis Nolte,Raoul Falk,Nils Kopal), Uni Duisburg-Essen
3
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7
8       http://www.apache.org/licenses/LICENSE-2.0
9
10   Unless required by applicable law or agreed to in writing, software
11   distributed under the License is distributed on an "AS IS" BASIS,
12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   See the License for the specific language governing permissions and
14   limitations under the License.
15*/
16
17using System;
18using System.Collections;
19using System.Linq;
20using System.Text;
21using Cryptool.PluginBase;
22using Cryptool.PluginBase.IO;
23using Cryptool.PluginBase.Miscellaneous;
24using System.ComponentModel;
25using System.Threading;
26using System.IO;
27using System.Windows.Controls;
28using System.Windows.Threading;
29using System.Windows;
30using System.Reflection;
31using System.Numerics;
32using System.Collections.Generic;
33using System.Diagnostics;
34using Cryptool.P2P;
35
36namespace Cryptool.Plugins.QuadraticSieve
37{
38    /// <summary>
39    /// This class wraps the msieve algorithm in version 1.42 which you can find at http://www.boo.net/~jasonp/qs.html
40    /// It also extends the msieve functionality to multi threading
41    /// Many thanks to the author of msieve "jasonp_sf"
42    ///
43    /// For further information on quadratic sieve or msieve please have a look at the above mentioned URL
44    /// </summary>
45    [Author("Sven Rech", "rech@cryptool.org", "Uni Duisburg-Essen", "http://www.uni-due.de")]
46    [PluginInfo(false, "Quadratic Sieve", "Sieving Primes", "QuadraticSieve/DetailedDescription/Description.xaml", "QuadraticSieve/iconqs.png")]
47    class QuadraticSieve : DependencyObject, IThroughput
48    {
49        #region private variables
50
51        private readonly string directoryName;
52        private QuadraticSieveSettings settings;
53        private BigInteger inputNumber;
54        private BigInteger[] outputFactors;
55        private bool running;
56        private Queue relationPackageQueue;
57        private AutoResetEvent newRelationPackageEvent = new AutoResetEvent(false);
58        private IntPtr obj = IntPtr.Zero;
59        private volatile int threadcount = 0;
60        private ArrayList conf_list;
61        private Mutex conf_listMutex = new Mutex();
62        private bool userStopped = false;
63        private FactorManager factorManager;
64        private PeerToPeer peerToPeer;
65        private bool usePeer2Peer;
66        private bool useGnuplot = false;
67        private StreamWriter gnuplotFile;
68        private double[] relationsPerMS;
69
70        private static Assembly msieveDLL = null;
71        private static Type msieve = null;
72        private static bool alreadyInUse = false;
73        private static Mutex alreadyInUseMutex = new Mutex();
74        private AutoResetEvent waitForConnection = new AutoResetEvent(false);
75
76        #endregion
77
78        #region events
79
80        public event StatusChangedEventHandler OnPluginStatusChanged;
81        public event GuiLogNotificationEventHandler OnGuiLogNotificationOccured;
82        public event PluginProgressChangedEventHandler OnPluginProgressChanged;
83        public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
84        public event PluginProgressChangedEventHandler OnPluginProcessChanged;
85
86        #endregion
87
88        #region public
89
90        /// <summary>
91        /// Constructor
92        ///
93        /// constructs a new QuadraticSieve plugin
94        /// </summary>
95        public QuadraticSieve()
96        {
97            Settings = new QuadraticSieveSettings();
98
99            directoryName = Path.Combine(DirectoryHelper.DirectoryLocalTemp, "msieve");
100            if (!Directory.Exists(directoryName)) Directory.CreateDirectory(directoryName);
101
102            QuickWatchPresentation = new QuadraticSievePresentation();
103
104            peerToPeer = new PeerToPeer(quadraticSieveQuickWatchPresentation, newRelationPackageEvent);
105            peerToPeer.P2PWarning += new PeerToPeer.P2PWarningHandler(peerToPeer_P2PWarning);
106           
107            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
108            {
109                quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;               
110                quadraticSieveQuickWatchPresentation.timeLeft.Text = "?";
111                quadraticSieveQuickWatchPresentation.endTime.Text = "?";
112                quadraticSieveQuickWatchPresentation.logging.Text = "Currently not sieving.";
113            }
114            , null);
115        }
116
117        /// <summary>
118        /// Getter / Setter for the settings of this plugin
119        /// </summary>
120        public Cryptool.PluginBase.ISettings Settings
121        {
122            get { return this.settings; }
123            set
124            {
125                this.settings = (QuadraticSieveSettings)value;
126                this.settings.PropertyChanged += new PropertyChangedEventHandler(settings_PropertyChanged);
127            }
128        }
129
130        private void settings_PropertyChanged(object sender, PropertyChangedEventArgs e)
131        {
132            if (e.PropertyName == "UsePeer2Peer")
133            {
134                if (quadraticSieveQuickWatchPresentation != null)
135                {
136                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
137                    {
138                        quadraticSieveQuickWatchPresentation.peer2peer.Visibility = settings.UsePeer2Peer ? Visibility.Visible : Visibility.Collapsed;                       
139                    }, null);
140                }
141            }
142        }
143
144        /// <summary>
145        /// Called by the environment before executing this plugin
146        /// </summary>
147        public void PreExecution()
148        { 
149        }
150       
151        /// <summary>
152        /// Called by the environment to execute this plugin
153        /// </summary>
154        public void Execute()
155        {
156            if (checkInUse())
157                return;
158
159            try
160            {
161                usePeer2Peer = settings.UsePeer2Peer;
162                if (usePeer2Peer && !P2PManager.IsConnected && P2PManager.IsConnecting)
163                {
164                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred += HandleConnectionStateChange;
165                    GuiLogMessage("Connecting to Peer2Peer network... Please wait!", NotificationLevel.Info);
166                    waitForConnection.WaitOne();                   
167                    P2PManager.ConnectionManager.OnP2PConnectionStateChangeOccurred -= HandleConnectionStateChange;
168                }
169                else if (usePeer2Peer && !P2PManager.IsConnected)
170                {
171                    GuiLogMessage("No connection to Peer2Peer network. Sieving locally now!", NotificationLevel.Warning);
172                    usePeer2Peer = false;
173                }
174
175                if (usePeer2Peer && settings.Channel.Trim() == "")
176                {
177                    GuiLogMessage("No channel for Peer2Peer network specified. Sieving locally now!", NotificationLevel.Warning);
178                    usePeer2Peer = false;
179                }
180                if (usePeer2Peer)
181                {
182                    peerToPeer.SetChannel(settings.Channel);
183                    peerToPeer.SetNumber(InputNumber);
184                }
185
186                if (useGnuplot)
187                    gnuplotFile = new StreamWriter(Path.Combine(directoryName, "gnuplot.dat"), false);
188
189                userStopped = false;
190
191                if (InputNumber != 0)
192                {
193                    if (InputNumber.ToString().Length >= 275)
194                    {
195                        GuiLogMessage("Input too big.", NotificationLevel.Error);
196                        return;
197                    }
198
199                    String timeLeft_message = "?";
200                    String endtime_message = "?";
201                    String logging_message = "Starting quadratic sieve, please wait!";
202
203                    GuiLogMessage(logging_message, NotificationLevel.Info);
204                    quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
205                    {
206                        quadraticSieveQuickWatchPresentation.ProgressRelationPackages.Clear();
207                        quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
208                        quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
209                        quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
210                        quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
211                        quadraticSieveQuickWatchPresentation.factorInfo.Content = "Searching trivial factors!";
212                        if (usePeer2Peer)
213                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
214                        else
215                            quadraticSieveQuickWatchPresentation.relationsInfo.Content = "Only local sieving!";
216                    }
217                    , null);
218
219                    DateTime start_time = DateTime.Now;
220
221                    initMsieveDLL();
222                    factorManager = new FactorManager(msieve.GetMethod("getPrimeFactors"), msieve.GetMethod("getCompositeFactors"), InputNumber);
223                    factorManager.FactorsChanged += this.FactorsChanged;
224
225                    //Now factorize:               
226                    try
227                    {
228                        string file = Path.Combine(directoryName, "" + InputNumber + ".dat");
229                        if (settings.DeleteCache && File.Exists(file))
230                            File.Delete(file);
231                        MethodInfo start = msieve.GetMethod("start");
232                        start.Invoke(null, new object[] { InputNumber.ToString(), file });
233                        obj = IntPtr.Zero;
234                    }
235                    catch (Exception ex)
236                    {
237                        GuiLogMessage("Error using msieve. " + ex.Message, NotificationLevel.Error);
238                        stopThreads();
239                        return;
240                    }
241
242                    if (!userStopped)
243                    {
244                        timeLeft_message = "0 seconds left";
245                        endtime_message = "" + (DateTime.Now);
246                        logging_message = "Sieving finished in " + (DateTime.Now - start_time) + "!";
247
248                        GuiLogMessage(logging_message, NotificationLevel.Info);
249                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
250                        {
251                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
252                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
253                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
254                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
255                        }
256                        , null);
257
258                        Debug.Assert(factorManager.CalculateNumber() == InputNumber);
259                        OutputFactors = factorManager.getPrimeFactors();
260                    }
261                    else
262                    {
263                        timeLeft_message = "0 sec left";
264                        endtime_message = "Stopped";
265                        logging_message = "Stopped by user!";
266
267                        GuiLogMessage(logging_message, NotificationLevel.Info);
268                        quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
269                        {
270                            quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
271                            quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
272                            quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
273                            quadraticSieveQuickWatchPresentation.factorInfo.Content = "";
274                        }
275                        , null);
276                    }
277
278                    ProgressChanged(1, 1);
279
280                }
281                if (useGnuplot)
282                    gnuplotFile.Close();
283            }
284            finally
285            {
286                alreadyInUse = false;
287            }
288        }
289
290        private void HandleConnectionStateChange(object sender, bool newState)
291        {
292            waitForConnection.Set();
293        }
294
295        private bool checkInUse()
296        {
297            try
298            {
299                alreadyInUseMutex.WaitOne();
300                if (alreadyInUse)
301                {
302                    GuiLogMessage("QuadraticSieve plugin is only allowed to execute ones at a time due to technical restrictions.", NotificationLevel.Error);
303                    return true;
304                }
305                else
306                {
307                    alreadyInUse = true;
308                    return false;
309                }
310            }
311            finally
312            {
313                alreadyInUseMutex.ReleaseMutex();
314            }
315        }
316       
317        /// <summary>
318        /// Called by the environment after execution
319        /// </summary>
320        public void PostExecution()
321        {
322        }
323
324        /// <summary>
325        /// Called by the environment to pause execution
326        /// </summary>
327        public void Pause()
328        {
329        }
330
331        /// <summary>
332        /// Called by the environment to stop execution
333        /// </summary>
334        public void Stop()
335        {
336            this.userStopped = true;
337            if (obj != IntPtr.Zero)
338            {
339                stopThreads();
340                MethodInfo stop = msieve.GetMethod("stop");
341                stop.Invoke(null, new object[] { obj });
342            }
343
344        }
345
346        /// <summary>
347        /// Called by the environment to initialize this plugin
348        /// </summary>
349        public void Initialize()
350        {
351            settings.Initialize();
352        }
353
354        /// <summary>
355        /// Called by the environment to dispose this plugin
356        /// </summary>
357        public void Dispose()
358        {
359        }
360
361        /// <summary>
362        /// Getter / Setter for the input number which should be factorized
363        /// </summary>
364        [PropertyInfo(Direction.InputData, "Number input", "Enter the number you want to factorize", "", DisplayLevel.Beginner)]
365        public BigInteger InputNumber
366        {
367            get
368            {
369                return inputNumber;
370            }
371            set
372            {
373                this.inputNumber = value;
374                OnPropertyChanged("InputNumber");
375            }
376        }
377
378        /// <summary>
379        /// Getter / Setter for the factors calculated by msieve
380        /// </summary>
381        [PropertyInfo(Direction.OutputData, "Factors output", "Your factors will be sent here", "", DisplayLevel.Beginner)]
382        public BigInteger[] OutputFactors
383        {
384            get
385            {
386                return outputFactors;
387            }
388            set
389            {
390                this.outputFactors = value;
391                OnPropertyChanged("OutputFactors");
392            }
393        }
394       
395        /// <summary>
396        /// Called when a property of this plugin changes
397        /// </summary>
398        /// <param name="name">name</param>
399        public void OnPropertyChanged(string name)
400        {
401            EventsHelper.PropertyChanged(PropertyChanged, this, new PropertyChangedEventArgs(name));
402        }
403
404        /// <summary>
405        /// Getter / Setter for the presentation of this plugin
406        /// </summary>
407        public UserControl Presentation { get; private set; }
408
409        /// <summary>
410        /// Getter / Setter for the QuickWatchPresentation of this plugin
411        /// </summary>
412        public UserControl QuickWatchPresentation
413        {
414            get;
415            private set;
416        }
417
418        #endregion
419
420        #region private
421
422        /// <summary>
423        /// calculate a String which shows the timespan
424        ///
425        /// example
426        ///
427        ///     4 days
428        /// or
429        ///     2 minutes
430        /// </summary>
431        /// <param name="ts"></param>
432        /// <returns></returns>
433        private String showTimeSpan(TimeSpan ts)
434        {
435            String res = "";
436            if (ts.Days != 0)
437                res = ts.Days + " days ";
438            if (ts.Hours != 0 || res.Length != 0)
439                res += ts.Hours + " hours ";
440            if (ts.Minutes != 0)
441                res += ts.Minutes + " minutes";
442            if (res.Length == 0)
443                res += ts.Seconds + " seconds";
444            return res;
445        }
446
447        /// <summary>
448        /// Callback method to prepare sieving
449        /// Called by msieve
450        ///
451        /// </summary>
452        /// <param name="conf">pointer to configuration</param>
453        /// <param name="update">number of relations found</param>
454        /// <param name="core_sieve_fcn">pointer to internal sieve function of msieve</param>
455        private void prepareSieving(IntPtr conf, int update, IntPtr core_sieve_fcn, int max_relations)
456        {
457            int threads = Math.Min(settings.CoresUsed, Environment.ProcessorCount-1);
458            MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
459            this.obj = (IntPtr)getObjFromConf.Invoke(null, new object[] { conf });           
460            relationPackageQueue = Queue.Synchronized(new Queue());
461            conf_list = new ArrayList();
462
463            String message = "Start sieving using " + (threads + 1) + " cores!";
464            GuiLogMessage(message, NotificationLevel.Info);
465            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
466            {
467                quadraticSieveQuickWatchPresentation.logging.Text = message;
468                if (usePeer2Peer)
469                    quadraticSieveQuickWatchPresentation.relationsInfo.Content = "";
470            }
471            , null);         
472
473            ProgressChanged(0.1, 1.0);
474
475            running = true;
476            //start helper threads:
477            relationsPerMS = new double[threads + 1];
478            for (int i = 0; i < threads+1; i++)
479            {
480                MethodInfo cloneSieveConf = msieve.GetMethod("cloneSieveConf");
481                IntPtr clone = (IntPtr)cloneSieveConf.Invoke(null, new object[] { conf });               
482                conf_list.Add(clone);
483                WaitCallback worker = new WaitCallback(MSieveJob);
484                ThreadPool.QueueUserWorkItem(worker, new object[] { clone, update, core_sieve_fcn, relationPackageQueue, i });
485            }
486
487            //manage the relation packages of the other threads:
488            manageRelationPackages(conf, max_relations);  //this method returns as soon as there are enough relations found
489            if (userStopped)
490                return;
491
492            //sieving is finished now, so give some informations and stop threads:
493            ProgressChanged(0.9, 1.0);
494            GuiLogMessage("Sieving finished", NotificationLevel.Info);
495            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
496            {
497                quadraticSieveQuickWatchPresentation.timeLeft.Text = "";
498                quadraticSieveQuickWatchPresentation.endTime.Text = "";
499                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Found enough relations! Please wait...";
500            }, null);
501           
502            stopThreads();
503            if (relationPackageQueue != null)
504                relationPackageQueue.Clear();
505        }
506
507        /// <summary>
508        /// Manages the whole relation packages that are created during the sieving process by the other threads (and other peers).
509        /// Returns true, if enough relations have been found.
510        /// </summary>
511        private void manageRelationPackages(IntPtr conf, int max_relations)
512        {
513            MethodInfo serializeRelationPackage = msieve.GetMethod("serializeRelationPackage");
514            MethodInfo deserializeRelationPackage = msieve.GetMethod("deserializeRelationPackage");
515            MethodInfo getNumRelations = msieve.GetMethod("getNumRelations");
516            int num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
517            int start_relations = num_relations;
518            DateTime start_sieving_time = DateTime.Now;
519            MethodInfo saveRelationPackage = msieve.GetMethod("saveRelationPackage");
520
521            while (num_relations < max_relations)
522            {
523                ProgressChanged((double)num_relations / max_relations * 0.8 + 0.1, 1.0);
524               
525                newRelationPackageEvent.WaitOne();               //wait until there is a new relation package in the queue
526                if (userStopped)
527                    return;
528
529                while (relationPackageQueue.Count != 0)       //get all the results from the helper threads, and store them
530                {
531                    IntPtr relationPackage = (IntPtr)relationPackageQueue.Dequeue();                   
532
533                    if (usePeer2Peer)
534                    {
535                        byte[] serializedRelationPackage = (byte[])serializeRelationPackage.Invoke(null, new object[] { relationPackage });
536                        peerToPeer.Put(serializedRelationPackage);
537                    }
538
539                    saveRelationPackage.Invoke(null, new object[] { conf, relationPackage });
540                }
541
542                if (usePeer2Peer)
543                {
544                    Queue dhtqueue = peerToPeer.GetLoadedRelationPackagesQueue();
545                    while (dhtqueue.Count != 0)       //get all the loaded results from the DHT, and store them
546                    {
547                        byte[] relationPackage = (byte[])dhtqueue.Dequeue();
548                        IntPtr deserializedRelationPackage = (IntPtr)deserializeRelationPackage.Invoke(null, new object[] { relationPackage });
549                        saveRelationPackage.Invoke(null, new object[] { conf, deserializedRelationPackage });
550                    }
551                }
552
553                num_relations = (int)getNumRelations.Invoke(null, new object[] { conf });
554                showProgressPresentation(max_relations, num_relations, start_relations, start_sieving_time);
555
556                if (usePeer2Peer && !peerToPeer.SyncFactorManager(factorManager))   //another peer already finished sieving
557                {
558                    throw new AlreadySievedException();
559                }
560            }           
561        }
562
563        private void showProgressPresentation(int max_relations, int num_relations, int start_relations, DateTime start_sieving_time)
564        {
565            String logging_message = "Found " + num_relations + " of " + max_relations + " relations!";
566            double msleft = 0;
567
568            //calculate global performance in relations per ms:
569            double globalPerformance = 0;
570            foreach (double r in relationsPerMS)
571                globalPerformance += r;
572            if (usePeer2Peer)
573                globalPerformance += peerToPeer.GetP2PPerformance();
574
575            //Calculate the total time assuming that we can sieve 1 minute with the same performance:
576            double relationsCalculatableIn1Minute = 1000 * 60 * 1 * globalPerformance;
577            if (relationsCalculatableIn1Minute <= max_relations)
578            {
579                double p = ApproximatedPolynom(relationsCalculatableIn1Minute / max_relations);
580                double estimatedTotalTime = 1000 * 60 * 1 / p;
581
582                //Calculate the elapsed time assuming that we sieved with the same performance the whole time:
583                p = ApproximatedPolynom((double)num_relations / max_relations);
584                double estimatedElapsedTime = estimatedTotalTime * p;
585
586                //Calculate time left:
587                msleft = estimatedTotalTime - estimatedElapsedTime;
588                /*GuiLogMessage("Total: " + new TimeSpan(0, 0, 0, 0, (int)estimatedTotalTime), NotificationLevel.Info);
589                GuiLogMessage("Elapsed: " + new TimeSpan(0, 0, 0, 0, (int)estimatedElapsedTime), NotificationLevel.Info);*/
590            }           
591           
592            String timeLeft_message = "very soon";
593            String endtime_message = "very soon";
594            if (msleft > 0 && !double.IsInfinity(msleft))
595            {
596                TimeSpan ts = new TimeSpan(0, 0, 0, 0, (int)msleft);
597                timeLeft_message = showTimeSpan(ts) + " left";
598                endtime_message = "" + DateTime.Now.AddMilliseconds((long)msleft);
599            }
600
601            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
602            {
603                quadraticSieveQuickWatchPresentation.logging.Text = logging_message;
604                quadraticSieveQuickWatchPresentation.timeLeft.Text = timeLeft_message;
605                quadraticSieveQuickWatchPresentation.endTime.Text = endtime_message;
606            }, null);
607
608            if (useGnuplot)
609            {
610                double percentage = (double)num_relations / max_relations;
611                double time = (DateTime.Now - start_sieving_time).TotalSeconds;
612                gnuplotFile.WriteLine("" + time + "\t\t" + percentage);
613            }
614        }
615
616        private static double ApproximatedPolynom(double x)
617        {
618            double a = -3.55504;
619            double b = 8.62296;
620            double c = -7.75103;
621            double d = 3.65871;
622            double progress = a * x * x * x * x + b * x * x * x + c * x * x + d * x;
623            return progress;
624        }
625
626        /// <summary>
627        /// This callback method is called by msieve. "list" is the trivial factor list (i.e. it consists of the factors that have been found without
628        /// using the quadratic sieve algorithm).
629        /// The method then factors all the factors that are still composite by using the quadratic sieve.
630        /// </summary>
631        private void putTrivialFactorlist(IntPtr list, IntPtr obj)
632        {
633            //add the trivial factors to the factor list:
634            factorManager.AddFactors(list);
635
636            if (usePeer2Peer)
637                peerToPeer.SyncFactorManager(factorManager);
638           
639            MethodInfo msieve_run_core = msieve.GetMethod("msieve_run_core");
640
641            try
642            {
643                //Now factorize as often as needed:
644                while (!factorManager.OnlyPrimes())
645                {
646                    //get one composite factor, which we want to sieve now:
647                    BigInteger compositeFactor = factorManager.GetCompositeFactor();
648                    showFactorInformations(compositeFactor);
649                    if (usePeer2Peer)
650                        peerToPeer.SetFactor(compositeFactor);
651
652                    try
653                    {
654                        //now start quadratic sieve on it:               
655                        IntPtr resultList = (IntPtr)msieve_run_core.Invoke(null, new object[2] { obj, compositeFactor.ToString() });
656                        if (resultList == IntPtr.Zero)
657                            throw new NotSievableException();
658
659                        if (userStopped)
660                            return;
661
662                        factorManager.ReplaceCompositeByFactors(compositeFactor, resultList);   //add the result list to factorManager
663
664                        if (usePeer2Peer)
665                            peerToPeer.SyncFactorManager(factorManager);
666                    }
667                    catch (AlreadySievedException)
668                    {
669                        GuiLogMessage("Another peer already finished factorization of composite factor" + compositeFactor + ". Sieving next one...", NotificationLevel.Info);
670                    }
671                }
672            }
673            catch (NotSievableException)
674            {
675                GuiLogMessage("This number is not sievable by msieve (maybe input too long?)", NotificationLevel.Error);
676            }
677        }
678
679        private void showFactorInformations(BigInteger compositeFactor)
680        {
681            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
682            {
683                String compRep;
684                if (compositeFactor.ToString().Length < 6)
685                    compRep = compositeFactor.ToString();
686                else
687                    compRep = compositeFactor.ToString().Substring(0, 4) + "...";
688                quadraticSieveQuickWatchPresentation.factorInfo.Content = "Now sieving first composite factor! (" + compRep + ")";
689            }, null);
690        }
691
692        /// <summary>
693        /// Helper Thread for msieve, which sieves for relations:
694        /// </summary>
695        /// <param name="param">params</param>
696        private void MSieveJob(object param)
697        {
698            threadcount++;
699            object[] parameters = (object[])param;
700            IntPtr clone = (IntPtr)parameters[0];
701            int update = (int)parameters[1];
702            IntPtr core_sieve_fcn = (IntPtr)parameters[2];
703            Queue relationPackageQueue = (Queue)parameters[3];
704            int threadNR = (int)parameters[4];
705
706            try
707            {
708                MethodInfo collectRelations = msieve.GetMethod("collectRelations");
709                MethodInfo getRelationPackage = msieve.GetMethod("getRelationPackage");
710                MethodInfo getAmountOfRelationsInRelationPackage = msieve.GetMethod("getAmountOfRelationsInRelationPackage");
711
712                Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
713
714                while (running)
715                {
716                    try
717                    {
718                        //Calculate the performance of this thread:
719                        DateTime beginning = DateTime.Now;
720                        collectRelations.Invoke(null, new object[] { clone, update, core_sieve_fcn });
721                        IntPtr relationPackage = (IntPtr)getRelationPackage.Invoke(null, new object[] { clone });
722
723                        int amountOfFullRelations = (int)getAmountOfRelationsInRelationPackage.Invoke(null, new object[] { relationPackage });
724                        relationsPerMS[threadNR] = amountOfFullRelations / (DateTime.Now - beginning).TotalMilliseconds;
725
726                        if (usePeer2Peer)
727                            peerToPeer.SetOurPerformance(relationsPerMS);
728
729                        relationPackageQueue.Enqueue(relationPackage);
730                        newRelationPackageEvent.Set();
731                    }
732                    catch (Exception ex)
733                    {
734                        GuiLogMessage("Error using msieve." + ex.Message, NotificationLevel.Error);
735                        threadcount = 0;
736                        return;
737                    }
738                }
739
740                conf_listMutex.WaitOne();
741                if (conf_list != null)
742                    conf_list[threadNR] = null;
743                MethodInfo freeSieveConf = msieve.GetMethod("freeSieveConf");
744                freeSieveConf.Invoke(null, new object[] { clone });
745                conf_listMutex.ReleaseMutex();
746            }
747            finally
748            {
749                threadcount--;
750            }
751        }       
752
753        /// <summary>
754        /// Stop all running threads
755        /// </summary>
756        private void stopThreads()
757        {
758            if (conf_list != null)
759            {
760                running = false;               
761
762                MethodInfo stop = msieve.GetMethod("stop");
763                MethodInfo getObjFromConf = msieve.GetMethod("getObjFromConf");
764
765                conf_listMutex.WaitOne();
766                foreach (Object conf in conf_list)
767                    if (conf != null)
768                        stop.Invoke(null, new object[] { getObjFromConf.Invoke(null, new object[] { (IntPtr)conf }) });
769
770                conf_list = null;
771                conf_listMutex.ReleaseMutex();
772
773                if (usePeer2Peer)
774                    peerToPeer.StopLoadStoreThread();
775
776                GuiLogMessage("Waiting for threads to stop!", NotificationLevel.Debug);
777                while (threadcount > 0)
778                {
779                    Thread.Sleep(0);
780                }
781                GuiLogMessage("Threads stopped!", NotificationLevel.Debug);
782            }
783        }   
784
785        /// <summary>
786        /// Change the progress of this plugin
787        /// </summary>
788        /// <param name="value">value</param>
789        /// <param name="max">max</param>
790        private void ProgressChanged(double value, double max)
791        {
792            EventsHelper.ProgressChanged(OnPluginProgressChanged, this, new PluginProgressEventArgs(value, max));
793        }
794
795        private void FactorsChanged(List<BigInteger> primeFactors, List<BigInteger> compositeFactors)
796        {
797            quadraticSieveQuickWatchPresentation.Dispatcher.Invoke(DispatcherPriority.Normal, (SendOrPostCallback)delegate
798            {
799                quadraticSieveQuickWatchPresentation.factorList.Items.Clear();
800
801                foreach (BigInteger pf in primeFactors)         
802                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Prime Factor: " + pf.ToString());           
803
804                foreach (BigInteger cf in compositeFactors)
805                    quadraticSieveQuickWatchPresentation.factorList.Items.Add("Composite Factor: " + cf.ToString());
806            }, null);
807        }
808
809        /// <summary>
810        /// Logs a message to the CrypTool gui
811        /// </summary>
812        /// <param name="p">p</param>
813        /// <param name="notificationLevel">notificationLevel</param>
814        private void GuiLogMessage(string p, NotificationLevel notificationLevel)
815        {
816            EventsHelper.GuiLogMessage(OnGuiLogNotificationOccured, this, new GuiLogEventArgs(p, this, notificationLevel));
817        }
818
819        /// <summary>
820        /// Getter / Setter for the QuickWatchPresentation
821        /// </summary>
822        private QuadraticSievePresentation quadraticSieveQuickWatchPresentation
823        {
824            get { return QuickWatchPresentation as QuadraticSievePresentation; }
825        }
826
827        /// <summary>
828        /// dynamically loads the msieve dll file and sets the callbacks
829        /// </summary>
830        private void initMsieveDLL()
831        {
832            //Load msieve.dll (if necessary):
833            if (msieve == null || msieveDLL == null)
834            {
835                string s = Directory.GetCurrentDirectory();
836                string dllname;
837                if (IntPtr.Size == 4)
838                    dllname = "msieve.dll";
839                else
840                    dllname = "msieve64.dll";
841
842                msieveDLL = Assembly.LoadFile(Directory.GetCurrentDirectory() + "\\AppReferences\\"  + dllname);
843                msieve = msieveDLL.GetType("Msieve.msieve");
844            }
845
846            //init msieve with callbacks:
847            MethodInfo initMsieve = msieve.GetMethod("initMsieve");
848            Object callback_struct = Activator.CreateInstance(msieveDLL.GetType("Msieve.callback_struct"));           
849            FieldInfo prepareSievingField = msieveDLL.GetType("Msieve.callback_struct").GetField("prepareSieving");
850            FieldInfo putTrivialFactorlistField = msieveDLL.GetType("Msieve.callback_struct").GetField("putTrivialFactorlist");           
851            Delegate prepareSievingDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.prepareSievingDelegate"), this, "prepareSieving");
852            Delegate putTrivialFactorlistDel = MulticastDelegate.CreateDelegate(msieveDLL.GetType("Msieve.putTrivialFactorlistDelegate"), this, "putTrivialFactorlist");           
853            prepareSievingField.SetValue(callback_struct, prepareSievingDel);
854            putTrivialFactorlistField.SetValue(callback_struct, putTrivialFactorlistDel);
855            initMsieve.Invoke(null, new object[1] { callback_struct });
856        }
857
858        private void peerToPeer_P2PWarning(string warning)
859        {
860            GuiLogMessage(warning, NotificationLevel.Warning);
861        }
862
863        #endregion
864
865    }
866}
Note: See TracBrowser for help on using the repository browser.